diff --git a/compat/Android.common.mk b/compat/Android.common.mk new file mode 100644 index 000000000..4a5b4186d --- /dev/null +++ b/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) diff --git a/compat/camera/Android.mk b/compat/camera/Android.mk new file mode 100644 index 000000000..431590eaf --- /dev/null +++ b/compat/camera/Android.mk @@ -0,0 +1,63 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../Android.common.mk + +HYBRIS_PATH := $(LOCAL_PATH)/../../hybris + +LOCAL_SRC_FILES := camera_compatibility_layer.cpp + +LOCAL_MODULE := libcamera_compat_layer +LOCAL_MODULE_TAGS := optional + +LOCAL_C_INCLUDES := \ + $(HYBRIS_PATH)/include + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libcamera_client \ + libutils \ + libbinder \ + libhardware \ + libui \ + libgui + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +HYBRIS_PATH := $(LOCAL_PATH)/../../hybris + +LOCAL_SRC_FILES := direct_camera_test.cpp + +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 \ + bionic \ + bionic/libstdc++/include \ + external/gtest/include \ + external/stlport/stlport \ + external/skia/include/core \ + +LOCAL_SHARED_LIBRARIES := \ + libis_compat_layer \ + libsf_compat_layer \ + libcamera_compat_layer \ + libmedia_compat_layer \ + libcutils \ + libcamera_client \ + libutils \ + libbinder \ + libhardware \ + libui \ + libgui \ + libEGL \ + libGLESv2 + +include $(BUILD_EXECUTABLE) diff --git a/compat/camera/camera_compatibility_layer.cpp b/compat/camera/camera_compatibility_layer.cpp new file mode 100644 index 000000000..435c5936a --- /dev/null +++ b/compat/camera/camera_compatibility_layer.cpp @@ -0,0 +1,1049 @@ +/* + * 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: Thomas Voß + * Ricardo Salveti de Araujo + * Jim Hodapp + */ + +//#define LOG_NDEBUG 0 + +#include +#include +#include +#include + +#include + +#include +#include +#include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +#include +#else +#include +#endif +#if ANDROID_VERSION_MAJOR>=5 +#include +#endif +#include + +#include +#include + +#undef LOG_TAG +#define LOG_TAG "CameraCompatibilityLayer" +#include +#include +#include +#include +#include + +#include + +#include + +#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__) + +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) + listener->on_preview_texture_needs_update_cb(listener->context); +} + +// From android::CameraListener +void CameraControl::notify(int32_t msg_type, int32_t ext1, int32_t ext2) +{ + REPORT_FUNCTION(); + printf("\text1: %d, ext2: %d \n", ext1, ext2); + + if (!listener) + return; + + switch (msg_type) { + case CAMERA_MSG_ERROR: + if (listener->on_msg_error_cb) + listener->on_msg_error_cb(listener->context); + break; + case CAMERA_MSG_SHUTTER: + if (listener->on_msg_shutter_cb) + listener->on_msg_shutter_cb(listener->context); + break; + case CAMERA_MSG_ZOOM: + if (listener->on_msg_zoom_cb) + listener->on_msg_zoom_cb(listener->context, ext1); + break; + case CAMERA_MSG_FOCUS: + if (listener->on_msg_focus_cb) + listener->on_msg_focus_cb(listener->context); + break; + default: + break; + } +} + +void CameraControl::postData( + int32_t msg_type, + const android::sp& data, + camera_frame_metadata_t* metadata) +{ + REPORT_FUNCTION(); + + if (!listener) + return; + + switch (msg_type) { + case CAMERA_MSG_RAW_IMAGE: + if (listener->on_data_raw_image_cb) + listener->on_data_raw_image_cb(data->pointer(), data->size(), listener->context); + break; + case CAMERA_MSG_COMPRESSED_IMAGE: + 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; + } +} + +void CameraControl::postDataTimestamp( + nsecs_t timestamp, + int32_t msg_type, + const android::sp& data) +{ + REPORT_FUNCTION(); + (void) timestamp; + (void) msg_type; + (void) data; +} + +namespace android +{ +NativeBufferAlloc::NativeBufferAlloc() { +} + +NativeBufferAlloc::~NativeBufferAlloc() { +} + +sp NativeBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, + PixelFormat format, uint32_t usage, status_t* error) { + sp 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; +} +} + +int android_camera_get_number_of_devices() +{ + REPORT_FUNCTION(); + return android::Camera::getNumberOfCameras(); +} + +int android_camera_get_device_info(int32_t camera_id, int* facing, int* orientation) +{ + REPORT_FUNCTION(); + + if (!facing || !orientation) + return android::BAD_VALUE; + + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CAMERA_FACING_BACK == static_cast(BACK_FACING_CAMERA_TYPE)); + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(CAMERA_FACING_FRONT == static_cast(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(); + + const int32_t camera_count = android::Camera::getNumberOfCameras(); + + 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) + continue; + + return android_camera_connect_by_id(camera_id, listener); + } + + 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; + + android::sp 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()); + + // 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.get(); +} + +void android_camera_disconnect(CameraControl* control) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + if (control->preview_texture != NULL) + control->preview_texture->abandon(); + + control->camera->disconnect(); + control->camera->unlock(); +} + +int android_camera_lock(CameraControl* control) +{ + android::Mutex::Autolock al(control->guard); + return control->camera->lock(); +} + +int android_camera_unlock(CameraControl* control) +{ + android::Mutex::Autolock al(control->guard); + return control->camera->unlock(); +} + +void android_camera_delete(CameraControl* control) +{ + android::sp camera = control->camera; + control->camera.clear(); + camera.clear(); +} + +void android_camera_dump_parameters(CameraControl* control) +{ + REPORT_FUNCTION(); + assert(control); + + printf("%s \n", control->camera->getParameters().string()); +} + +void android_camera_set_flash_mode(CameraControl* control, FlashMode mode) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + control->camera_parameters.set( + android::CameraParameters::KEY_FLASH_MODE, + flash_modes[mode]); + control->camera->setParameters(control->camera_parameters.flatten()); +} + +void android_camera_get_flash_mode(CameraControl* control, FlashMode* mode) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + static const char* flash_mode = control->camera_parameters.get( + android::CameraParameters::KEY_FLASH_MODE); + if (flash_mode) + *mode = flash_modes_lut.valueFor(android::String8(flash_mode)); + else + *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(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + control->camera_parameters.set( + android::CameraParameters::KEY_WHITE_BALANCE, + white_balance_modes[mode]); + control->camera->setParameters(control->camera_parameters.flatten()); +} + +void android_camera_get_white_balance_mode(CameraControl* control, WhiteBalanceMode* mode) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + *mode = white_balance_modes_lut.valueFor( + android::String8( + control->camera_parameters.get( + android::CameraParameters::KEY_WHITE_BALANCE))); +} + +void android_camera_set_scene_mode(CameraControl* control, SceneMode mode) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + control->camera_parameters.set( + android::CameraParameters::KEY_SCENE_MODE, + scene_modes[mode]); + 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(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + *mode = scene_modes_lut.valueFor( + android::String8( + control->camera_parameters.get( + android::CameraParameters::KEY_SCENE_MODE))); +} + +void android_camera_set_auto_focus_mode(CameraControl* control, AutoFocusMode mode) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + control->camera_parameters.set( + android::CameraParameters::KEY_FOCUS_MODE, + auto_focus_modes[mode]); + control->camera->setParameters(control->camera_parameters.flatten()); +} + +void android_camera_get_auto_focus_mode(CameraControl* control, AutoFocusMode* mode) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + *mode = auto_focus_modes_lut.valueFor( + android::String8( + control->camera_parameters.get( + android::CameraParameters::KEY_FOCUS_MODE))); +} + + +void android_camera_set_effect_mode(CameraControl* control, EffectMode mode) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + control->camera_parameters.set( + android::CameraParameters::KEY_EFFECT, + effect_modes[mode]); + control->camera->setParameters(control->camera_parameters.flatten()); +} + +void android_camera_get_effect_mode(CameraControl* control, EffectMode* mode) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + *mode = effect_modes_lut.valueFor( + android::String8( + control->camera_parameters.get( + android::CameraParameters::KEY_EFFECT))); +} + +void android_camera_get_preview_fps_range(CameraControl* control, int* min, int* max) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + control->camera_parameters.getPreviewFpsRange(min, max); +} + +void android_camera_set_preview_fps(CameraControl* control, int fps) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + control->camera_parameters.setPreviewFrameRate(fps); + control->camera->setParameters(control->camera_parameters.flatten()); +} + +void android_camera_get_preview_fps(CameraControl* control, int* fps) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + *fps = control->camera_parameters.getPreviewFrameRate(); +} + +void android_camera_enumerate_supported_preview_sizes(CameraControl* control, size_callback cb, void* ctx) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + android::Vector sizes; + control->camera_parameters.getSupportedPreviewSizes(sizes); + + for (unsigned int i = 0; i < sizes.size(); i++) { + cb(ctx, sizes[i].width, sizes[i].height); + } +} + +void android_camera_enumerate_supported_picture_sizes(CameraControl* control, size_callback cb, void* ctx) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + android::Vector sizes; + control->camera_parameters.getSupportedPictureSizes(sizes); + + for (unsigned int i = 0; i < sizes.size(); i++) { + cb(ctx, sizes[i].width, sizes[i].height); + } +} + +void android_camera_get_preview_size(CameraControl* control, int* width, int* height) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + control->camera_parameters.getPreviewSize(width, height); +} + +void android_camera_set_preview_size(CameraControl* control, int width, int height) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + control->camera_parameters.setPreviewSize(width, height); + control->camera->setParameters(control->camera_parameters.flatten()); +} + +void android_camera_get_picture_size(CameraControl* control, int* width, int* height) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + 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 xx 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 x pair + token = strtok_r(NULL, delimiter, &save_ptr); + } +} + +void android_camera_set_picture_size(CameraControl* control, int width, int height) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + control->camera_parameters.setPictureSize(width, height); + control->camera->setParameters(control->camera_parameters.flatten()); +} + +void android_camera_get_current_zoom(CameraControl* control, int* zoom) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + *zoom = control->camera_parameters.getInt(android::CameraParameters::KEY_ZOOM); +} + +void android_camera_get_max_zoom(CameraControl* control, int* zoom) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + *zoom = control->camera_parameters.getInt(android::CameraParameters::KEY_MAX_ZOOM); +} + +void android_camera_set_display_orientation(CameraControl* control, int32_t clockwise_rotation_degree) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + static const int32_t ignored_parameter = 0; + control->camera->sendCommand(CAMERA_CMD_SET_DISPLAY_ORIENTATION, clockwise_rotation_degree, ignored_parameter); +} + +void android_camera_get_preview_texture_transformation(CameraControl* control, float m[16]) +{ + REPORT_FUNCTION(); + assert(control); + + if (control->preview_texture == NULL) + return; + + control->preview_texture->getTransformMatrix(m); +} + +void android_camera_update_preview_texture(CameraControl* control) +{ + REPORT_FUNCTION(); + assert(control); + + control->preview_texture->updateTexImage(); +} + +void android_camera_set_preview_texture(CameraControl* control, int texture_id) +{ + REPORT_FUNCTION(); + assert(control); + + static const bool allow_synchronous_mode = false; + static const bool is_controlled_by_app = true; + + android::sp native_alloc( + new android::NativeBufferAlloc() + ); + +#if ANDROID_VERSION_MAJOR>=5 + android::sp producer; + android::sp consumer; + android::BufferQueue::createBufferQueue(&producer, &consumer); +#else + android::sp 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( + new android::SurfaceTexture( +#else + control->preview_texture = android::sp( + 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(control)); +#else + android::sp(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(); + assert(control); + assert(surface); + + android::Mutex::Autolock al(control->guard); + control->camera->setPreviewDisplay(surface->surface); +} +#endif + +void android_camera_start_preview(CameraControl* control) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + control->camera->startPreview(); +} + +void android_camera_stop_preview(CameraControl* control) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + control->camera->stopPreview(); +} + +void android_camera_start_autofocus(CameraControl* control) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + control->camera->autoFocus(); +} + +void android_camera_stop_autofocus(CameraControl* control) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + control->camera->cancelAutoFocus(); +} + +void android_camera_start_zoom(CameraControl* control, int32_t zoom) +{ + REPORT_FUNCTION(); + assert(control); + + static const int ignored_argument = 0; + + android::Mutex::Autolock al(control->guard); + control->camera->sendCommand(CAMERA_CMD_START_SMOOTH_ZOOM, + zoom, + ignored_argument); +} + +// Adjust the zoom level immediately as opposed to smoothly zoomin gin. +void android_camera_set_zoom(CameraControl* control, int32_t zoom) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + control->camera_parameters.set( + android::CameraParameters::KEY_ZOOM, + zoom); + + control->camera->setParameters(control->camera_parameters.flatten()); +} + +void android_camera_stop_zoom(CameraControl* control) +{ + REPORT_FUNCTION(); + assert(control); + + static const int ignored_argument = 0; + + android::Mutex::Autolock al(control->guard); + control->camera->sendCommand(CAMERA_CMD_STOP_SMOOTH_ZOOM, + ignored_argument, + ignored_argument); +} + +void android_camera_take_snapshot(CameraControl* control) +{ + REPORT_FUNCTION(); + assert(control); + android::Mutex::Autolock al(control->guard); + 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(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + control->camera_parameters.set( + android::CameraParameters::KEY_PREVIEW_FORMAT, + camera_pixel_formats[pf]); + + control->camera->setParameters(control->camera_parameters.flatten()); +} + +void android_camera_get_preview_format(CameraControl* control, CameraPixelFormat* pf) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + *pf = pixel_formats_lut.valueFor( + android::String8( + control->camera_parameters.get( + android::CameraParameters::KEY_PREVIEW_FORMAT))); +} + +void android_camera_set_focus_region( + CameraControl* control, + FocusRegion* region) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + static const char* focus_region_pattern = "(%d,%d,%d,%d,%d)"; + static char focus_region[256]; + snprintf(focus_region, + sizeof(focus_region), + focus_region_pattern, + region->left, + region->top, + region->right, + region->bottom, + region->weight); + + control->camera_parameters.set( + android::CameraParameters::KEY_FOCUS_AREAS, + focus_region); + + control->camera->setParameters(control->camera_parameters.flatten()); +} + +void android_camera_reset_focus_region(CameraControl* control) +{ + static FocusRegion region = { 0, 0, 0, 0, 0 }; + + android_camera_set_focus_region(control, ®ion); +} + +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, ®ion); +} + +void android_camera_set_rotation(CameraControl* control, int rotation) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + control->camera_parameters.set( + android::CameraParameters::KEY_ROTATION, + rotation); + 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(); + assert(control); + assert(cb); + + android::Mutex::Autolock al(control->guard); + android::Vector sizes; + control->camera_parameters.getSupportedVideoSizes(sizes); + + for (unsigned int i = 0; i < sizes.size(); i++) { + cb(ctx, sizes[i].width, sizes[i].height); + } +} + +void android_camera_get_video_size(CameraControl* control, int* width, int* height) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + control->camera_parameters.getVideoSize(width, height); +} + +void android_camera_set_video_size(CameraControl* control, int width, int height) +{ + REPORT_FUNCTION(); + assert(control); + + android::Mutex::Autolock al(control->guard); + + 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)); +} diff --git a/compat/camera/direct_camera_test.cpp b/compat/camera/direct_camera_test.cpp new file mode 100644 index 000000000..368158ebc --- /dev/null +++ b/compat/camera/direct_camera_test.cpp @@ -0,0 +1,683 @@ +/* + * 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: Thomas Voß + * Ricardo Salveti de Araujo + * Jim Hodapp + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +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() +{ + static EffectMode current_effect = EFFECT_MODE_NONE; + + EffectMode next = current_effect; + + switch (current_effect) { + case EFFECT_MODE_NONE: + next = EFFECT_MODE_MONO; + break; + case EFFECT_MODE_MONO: + next = EFFECT_MODE_NEGATIVE; + break; + case EFFECT_MODE_NEGATIVE: + next = EFFECT_MODE_SOLARIZE; + break; + case EFFECT_MODE_SOLARIZE: + next = EFFECT_MODE_SEPIA; + break; + case EFFECT_MODE_SEPIA: + next = EFFECT_MODE_POSTERIZE; + break; + case EFFECT_MODE_POSTERIZE: + next = EFFECT_MODE_WHITEBOARD; + break; + case EFFECT_MODE_WHITEBOARD: + next = EFFECT_MODE_BLACKBOARD; + break; + case EFFECT_MODE_BLACKBOARD: + next = EFFECT_MODE_AQUA; + break; + case EFFECT_MODE_AQUA: + next = EFFECT_MODE_NONE; + break; + } + + current_effect = next; + return next; +} + +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__); + + CameraControl* cc = static_cast(context); + static int zoom; + android_camera_get_current_zoom(cc, &zoom); + printf("\t Current zoom: %d\n", zoom); + 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); + + char fn[256]; + 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); + shot_counter++; + + CameraControl* cc = static_cast(context); + android_camera_start_preview(cc); +} + +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 thumbnail_size_cb(void* ctx, int width, int height) +{ + 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; + } +} + +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"; + } + + 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 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(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, ¶ms); + + 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; + 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; + camera_control = android_camera_connect_to(BACK_FACING_CAMERA_TYPE, + &listener); + + if (camera_control == NULL) { + printf("Problem connecting to camera"); + return 1; + } + listener.context = camera_control; + + AndroidEventListener event_listener; + event_listener.on_new_event = on_new_input_event; + event_listener.context = camera_control; + + 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(); + + // 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(camera_control, &min_fps, &max_fps); + printf("Preview fps range: [%d,%d]\n", min_fps, max_fps); + android_camera_get_preview_fps(camera_control, ¤t_fps); + printf("Current preview fps range: %d\n", current_fps); + +#if 0 + android_camera_dump_parameters(camera_control); + + android_camera_set_display_orientation(camera_control, 90); + + int 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(camera_control, &width, &height); + printf("Current picture size: [%d,%d]\n", width, height); + android_camera_get_current_zoom(camera_control, &zoom); + printf("Current zoom: %d \n", zoom); + + EffectMode effect_mode; + FlashMode flash_mode; + WhiteBalanceMode wb_mode; + //SceneMode scene_mode; + CameraPixelFormat 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); + 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); +#endif + android_camera_get_preview_format(camera_control, &pixel_format); + printf("Current preview pixel format: %d \n", pixel_format); + //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"); + + disp = sf_client_get_egl_display(cs.client); + surface = sf_surface_get_egl_surface(cs.surface); + + 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); + 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); + 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(camera_control, transformation_matrix); + glUniformMatrix4fv(render_data.matrix_loc, 1, GL_FALSE, transformation_matrix); + + printf("Started camera preview.\n"); + + while (1) { + usleep(50); + } + + stop_video_recording(recorder); + android_camera_stop_preview(camera_control); + android_camera_disconnect(camera_control); +} diff --git a/compat/input/Android.mk b/compat/input/Android.mk new file mode 100644 index 000000000..79c452571 --- /dev/null +++ b/compat/input/Android.mk @@ -0,0 +1,82 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../Android.common.mk + +HYBRIS_PATH := $(LOCAL_PATH)/../../hybris + +LOCAL_CFLAGS += -std=gnu++0x + +LOCAL_SRC_FILES:= input_compatibility_layer.cpp + +LOCAL_MODULE:= libis_compat_layer +LOCAL_MODULE_TAGS := optional + +LOCAL_SHARED_LIBRARIES := \ + libinput \ + libcutils \ + libutils \ + libskia \ + libgui \ + libandroidfw + +LOCAL_C_INCLUDES := \ + $(HYBRIS_PATH)/include \ + 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) + +include $(CLEAR_VARS) + +HYBRIS_PATH := $(LOCAL_PATH)/../../hybris + +LOCAL_CFLAGS += -std=gnu++0x + +LOCAL_SRC_FILES:= \ + direct_input_test.cpp + +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 \ + bionic \ + bionic/libstdc++/include \ + external/gtest/include \ + external/stlport/stlport \ + external/skia/include/core + +LOCAL_SHARED_LIBRARIES := \ + libis_compat_layer \ + libcutils \ + libutils \ + libskia \ + libgui \ + libandroidfw + +static_libraries := \ + libgtest \ + libgtest_main + +include $(BUILD_EXECUTABLE) diff --git a/compat/input/input_compatibility_layer.cpp b/compat/input/input_compatibility_layer.cpp new file mode 100644 index 000000000..19e5e490e --- /dev/null +++ b/compat/input/input_compatibility_layer.cpp @@ -0,0 +1,392 @@ +/* + * 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: Thomas Voß + * Ricardo Salveti de Araujo + */ + +#include + +#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 +#include + +#undef LOG_TAG +#define LOG_TAG "InputStackCompatibilityLayer" +#include + +namespace +{ +static bool enable_verbose_function_reporting = false; +} + +#define REPORT_FUNCTION() ALOGV("%s\n", __PRETTY_FUNCTION__); + +namespace +{ + +class DefaultPointerControllerPolicy : public android::PointerControllerPolicyInterface +{ +public: + static const size_t bitmap_width = 64; + static const size_t bitmap_height = 64; + + 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 + bitmap.eraseARGB(125, 0, 255, 0); + spotTouchIcon = android::SpriteIcon( + bitmap, + bitmap_width/2, + bitmap_height/2); + + // Icon for anchor touches + bitmap.eraseARGB(125, 0, 0, 255); + spotAnchorIcon = android::SpriteIcon( + bitmap, + bitmap_width/2, + bitmap_height/2); + + // Icon for hovering touches + bitmap.eraseARGB(125, 255, 0, 0); + spotHoverIcon = android::SpriteIcon( + bitmap, + bitmap_width/2, + bitmap_height/2); + } + + void loadPointerResources(android::PointerResources* outResources) + { + outResources->spotHover = spotHoverIcon.copy(); + outResources->spotTouch = spotTouchIcon.copy(); + outResources->spotAnchor = spotAnchorIcon.copy(); + } + + android::SpriteIcon spotHoverIcon; + android::SpriteIcon spotTouchIcon; + android::SpriteIcon spotAnchorIcon; + SkBitmap bitmap; +}; + +class DefaultInputReaderPolicyInterface : public android::InputReaderPolicyInterface +{ +public: + static const int32_t internal_display_id = android::ISurfaceComposer::eDisplayIdMain; + static const int32_t external_display_id = android::ISurfaceComposer::eDisplayIdHdmi; + + DefaultInputReaderPolicyInterface( + InputStackConfiguration* configuration, + const android::sp& looper) + : looper(looper), + default_layer_for_touch_point_visualization(configuration->default_layer_for_touch_point_visualization), + input_area_width(configuration->input_area_width), + input_area_height(configuration->input_area_height) + { + default_configuration.showTouches = configuration->enable_touch_point_visualization; + + android::DisplayViewport viewport; + viewport.setNonDisplayViewport(input_area_width, input_area_height); + viewport.displayId = android::ISurfaceComposer::eDisplayIdMain; + default_configuration.setDisplayInfo( + false, /* external */ + viewport); + } + + void getReaderConfiguration(android::InputReaderConfiguration* outConfig) + { + *outConfig = default_configuration; + } + + android::sp obtainPointerController(int32_t deviceId) + { + (void) deviceId; + + android::sp sprite_controller( + new android::SpriteController( + looper, + default_layer_for_touch_point_visualization)); + android::sp pointer_controller( + new android::PointerController( + android::sp(new DefaultPointerControllerPolicy()), + looper, + sprite_controller)); + pointer_controller->setPresentation( + android::PointerControllerInterface::PRESENTATION_SPOT); + + pointer_controller->setDisplayViewport(input_area_width, input_area_height, 0); + return pointer_controller; + } + + virtual void notifyInputDevicesChanged(const android::Vector& inputDevices) { + mInputDevices = inputDevices; + } + +#if ANDROID_VERSION_MAJOR<=4 + virtual android::sp getKeyboardLayoutOverlay(const android::String8& inputDeviceDescriptor) { +#elif ANDROID_VERSION_MAJOR>=5 + virtual android::sp getKeyboardLayoutOverlay(const android::InputDeviceIdentifier& identifier) { +#endif + return NULL; + } + + virtual android::String8 getDeviceAlias(const android::InputDeviceIdentifier& identifier) { + 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 looper; + int default_layer_for_touch_point_visualization; + android::InputReaderConfiguration default_configuration; + android::Vector mInputDevices; + int input_area_width; + int input_area_height; +}; + +class ExportedInputListener : public android::InputListenerInterface +{ +public: + ExportedInputListener(AndroidEventListener* external_listener) : external_listener(external_listener) + { + } + + void notifyConfigurationChanged(const android::NotifyConfigurationChangedArgs* args) + { + REPORT_FUNCTION(); + (void) args; + } + + void notifyKey(const android::NotifyKeyArgs* args) + { + REPORT_FUNCTION(); + + current_event.type = KEY_EVENT_TYPE; + current_event.device_id = args->deviceId; + current_event.source_id = args->source; + current_event.action = args->action; + current_event.flags = args->flags; + current_event.meta_state = args->metaState; + + current_event.details.key.key_code = args->keyCode; + current_event.details.key.scan_code = args->scanCode; + current_event.details.key.down_time = args->downTime; + current_event.details.key.event_time = args->eventTime; + + current_event.details.key.is_system_key = false; + + external_listener->on_new_event(¤t_event, external_listener->context); + } + + void notifyMotion(const android::NotifyMotionArgs* args) + { + REPORT_FUNCTION(); + + current_event.type = MOTION_EVENT_TYPE; + current_event.device_id = args->deviceId; + current_event.source_id = args->source; + current_event.action = args->action; + current_event.flags = args->flags; + current_event.meta_state = args->metaState; + + current_event.details.motion.button_state = args->buttonState; + current_event.details.motion.down_time = args->downTime; + current_event.details.motion.event_time = args->eventTime; + current_event.details.motion.edge_flags = args->edgeFlags; + current_event.details.motion.x_precision = args->xPrecision; + current_event.details.motion.y_precision = args->yPrecision; + current_event.details.motion.pointer_count = args->pointerCount; + + for (unsigned int i = 0; i < current_event.details.motion.pointer_count; i++) { + current_event.details.motion.pointer_coordinates[i].id = args->pointerProperties[i].id; + current_event.details.motion.pointer_coordinates[i].x + = current_event.details.motion.pointer_coordinates[i].raw_x + = args->pointerCoords[i].getX(); + current_event.details.motion.pointer_coordinates[i].y + = current_event.details.motion.pointer_coordinates[i].raw_y + = args->pointerCoords[i].getY(); + current_event.details.motion.pointer_coordinates[i].touch_major + = args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR); + current_event.details.motion.pointer_coordinates[i].touch_minor + = args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR); + current_event.details.motion.pointer_coordinates[i].pressure + = args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); + current_event.details.motion.pointer_coordinates[i].size + = args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE); + current_event.details.motion.pointer_coordinates[i].orientation + = args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); + + } + + external_listener->on_new_event(¤t_event, external_listener->context); + } + + void notifySwitch(const android::NotifySwitchArgs* args) + { + REPORT_FUNCTION(); + current_event.type = HW_SWITCH_EVENT_TYPE; + + current_event.details.hw_switch.event_time = args->eventTime; + current_event.details.hw_switch.policy_flags = args->policyFlags; + current_event.details.hw_switch.switch_values = args->switchValues; + current_event.details.hw_switch.switch_mask = args->switchMask; + + external_listener->on_new_event(¤t_event, external_listener->context); + } + + void notifyDeviceReset(const android::NotifyDeviceResetArgs* args) + { + REPORT_FUNCTION(); + (void) args; + } + +private: + AndroidEventListener* external_listener; + Event current_event; +}; + +class LooperThread : public android::Thread +{ +public: + static const int default_poll_timeout_ms = -1; + + LooperThread(const android::sp& looper) : looper(looper) + { + } + +private: + bool threadLoop() + { + if (ALOOPER_POLL_ERROR == looper->pollAll(default_poll_timeout_ms)) + return false; + return true; + } + + android::sp looper; +}; + +struct State : public android::RefBase +{ + State(AndroidEventListener* listener, + InputStackConfiguration* configuration) + : looper(new android::Looper(false)), + looper_thread(new LooperThread(looper)), + event_hub(new android::EventHub()), + input_reader_policy(new DefaultInputReaderPolicyInterface(configuration, looper)), + input_listener(new ExportedInputListener(listener)), + input_reader(new android::InputReader( + event_hub, + input_reader_policy, + input_listener)), + input_reader_thread(new android::InputReaderThread(input_reader)) + { + } + + ~State() + { + input_reader_thread->requestExit(); + } + + android::sp looper; + android::sp looper_thread; + + android::sp event_hub; + android::sp input_reader_policy; + android::sp input_listener; + android::sp input_reader; + android::sp input_reader_thread; + + android::Condition wait_condition; + android::Mutex wait_guard; +}; + +android::sp global_state; + +} + +void android_input_stack_initialize(AndroidEventListener* listener, InputStackConfiguration* config) +{ + global_state = new State(listener, config); +} + +void android_input_stack_loop_once() +{ + global_state->input_reader->loopOnce(); +} + +void android_input_stack_start() +{ + global_state->input_reader_thread->run(); + global_state->looper_thread->run(); +} + +void android_input_stack_start_waiting_for_flag(bool* flag) +{ + global_state->input_reader_thread->run(); + global_state->looper_thread->run(); + + while (!*flag) { + global_state->wait_condition.waitRelative( + global_state->wait_guard, + 10 * 1000 * 1000); + } +} + +void android_input_stack_stop() +{ + global_state->input_reader_thread->requestExit(); +} + +void android_input_stack_shutdown() +{ + global_state = NULL; +} diff --git a/compat/media/Android.mk b/compat/media/Android.mk new file mode 100644 index 000000000..289498337 --- /dev/null +++ b/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) diff --git a/compat/media/SimplePlayer.cpp b/compat/media/SimplePlayer.cpp new file mode 100644 index 000000000..cb5064c94 --- /dev/null +++ b/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 + +#include "SimplePlayer.h" + +#include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USE_MEDIA_CODEC_LAYER + +namespace android { + +SimplePlayer::SimplePlayer() + : mState(UNINITIALIZED), + mDoMoreStuffGeneration(0), + mStartTimeRealUs(-1ll) { +} + +SimplePlayer::~SimplePlayer() { +} + +// static +status_t PostAndAwaitResponse( + const sp &msg, sp *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 msg = new AMessage(kWhatSetDataSource, id()); + msg->setString("path", path); + sp response; + return PostAndAwaitResponse(msg, &response); +} + +status_t SimplePlayer::setSurface(const sp &surfaceTexture) { + sp msg = new AMessage(kWhatSetSurface, id()); + +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + sp surfaceTextureClient; + if (surfaceTexture != NULL) { + surfaceTextureClient = new SurfaceTextureClient(surfaceTexture); + } +#else + sp surfaceTextureClient; + if (surfaceTexture != NULL) { + surfaceTextureClient = new Surface(surfaceTexture); + } +#endif + + msg->setObject( + "native-window", new NativeWindowWrapper(surfaceTextureClient)); + + sp response; + return PostAndAwaitResponse(msg, &response); +} + +status_t SimplePlayer::prepare() { + sp msg = new AMessage(kWhatPrepare, id()); + sp response; + return PostAndAwaitResponse(msg, &response); +} + +status_t SimplePlayer::start() { + printf("%s\n", __PRETTY_FUNCTION__); + sp msg = new AMessage(kWhatStart, id()); + sp response; + return PostAndAwaitResponse(msg, &response); +} + +status_t SimplePlayer::stop() { + sp msg = new AMessage(kWhatStop, id()); + sp response; + return PostAndAwaitResponse(msg, &response); +} + +status_t SimplePlayer::reset() { + sp msg = new AMessage(kWhatReset, id()); + sp response; + return PostAndAwaitResponse(msg, &response); +} + +void SimplePlayer::onMessageReceived(const sp &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 response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatSetSurface: + { + status_t err; + if (mState != UNPREPARED) { + err = INVALID_OPERATION; + } else { + sp obj; + CHECK(msg->findObject("native-window", &obj)); + + mNativeWindow = static_cast(obj.get()); + + err = OK; + } + + uint32_t replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + sp 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 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 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 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 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 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 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 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; imCodecDelegate, 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 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 &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 &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 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 &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 &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 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 &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 diff --git a/compat/media/SimplePlayer.h b/compat/media/SimplePlayer.h new file mode 100644 index 000000000..d6512b07c --- /dev/null +++ b/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 +#include +#include + +#include + +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 &surfaceTexture); +#else + status_t setSurface(const sp &surfaceTexture); +#endif + status_t prepare(); + status_t start(); + status_t stop(); + status_t reset(); + +protected: + virtual ~SimplePlayer(); + + virtual void onMessageReceived(const sp &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 mCodec; + MediaCodecDelegate mCodecDelegate; + Vector > mCSD; + Vector > mBuffers[2]; + + List mAvailInputBufferIndices; + List mAvailOutputBufferInfos; + + sp mAudioTrack; + uint32_t mNumFramesWritten; + }; + + State mState; + AString mPath; + sp mNativeWindow; + + sp mExtractor; + sp mCodecLooper; + KeyedVector 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 &buffer); + + DISALLOW_EVIL_CONSTRUCTORS(SimplePlayer); +}; + +} // namespace android diff --git a/compat/media/camera_service.cpp b/compat/media/camera_service.cpp new file mode 100644 index 000000000..38bec4bed --- /dev/null +++ b/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 + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "CameraServiceCompatLayer" + +#include "media_recorder_factory.h" +#include "media_recorder.h" + +#include +#include + +#include + +#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(); +} diff --git a/compat/media/codec.cpp b/compat/media/codec.cpp new file mode 100644 index 000000000..fe3de4d49 --- /dev/null +++ b/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 + +#include "SimplePlayer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 mCodec; + Vector > mInBuffers; + Vector > mOutBuffers; + bool mSignalledInputEOS; + bool mSawOutputEOS; + int64_t mNumBuffersDecoded; + int64_t mNumBytesDecoded; + bool mIsAudio; +}; + +} // namespace android + +static int decode( + const android::sp &looper, + const char *path, + bool useAudio, + bool useVideo, + const android::sp &surface) { + using namespace android; + + static int64_t kTimeout = 500ll; + + sp extractor = new NuMediaExtractor; + if (extractor->setDataSource(path) != OK) { + fprintf(stderr, "unable to instantiate extractor.\n"); + return 1; + } + + KeyedVector stateByTrack; + + bool haveAudio = false; + bool haveVideo = false; + for (size_t i = 0; i < extractor->countTracks(); ++i) { + sp 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 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 &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 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 looper = new ALooper; + looper->start(); + + sp composerClient; + sp control; + sp surface; + + if (playback || (useSurface && useVideo)) { + composerClient = new SurfaceComposerClient; + CHECK_EQ(composerClient->initCheck(), (status_t)OK); + + sp 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 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; +} diff --git a/compat/media/decoding_service.cpp b/compat/media/decoding_service.cpp new file mode 100644 index 000000000..0905beefd --- /dev/null +++ b/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 + */ + +// Uncomment to enable verbose debug output +#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "DecodingService" + +#include "decoding_service_priv.h" + +#include +#include +#include +#include +#include + +typedef void* EGLDisplay; +typedef void* EGLSyncKHR; + +#include +#include +#include +#include +#include +#include + +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 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 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 binder = data.readStrongBinder(); + uint32_t handle = data.readInt32(); + sp 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* gbc) +{ + ALOGD("Entering %s", __PRETTY_FUNCTION__); + Parcel data, reply; + data.writeInterfaceToken(IDecodingService::getInterfaceDescriptor()); + remote()->transact(GET_IGRAPHICBUFFERCONSUMER, data, &reply); + *gbc = interface_cast(reply.readStrongBinder()); + return reply.readInt32(); +} + +status_t BpDecodingService::getIGraphicBufferProducer(sp* gbp) +{ + ALOGD("Entering %s", __PRETTY_FUNCTION__); + Parcel data, reply; + data.writeInterfaceToken(IDecodingService::getInterfaceDescriptor()); + remote()->transact(GET_IGRAPHICBUFFERPRODUCER, data, &reply); + *gbp = interface_cast(reply.readStrongBinder()); + return NO_ERROR; +} + +status_t BpDecodingService::registerSession(const sp& 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::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::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* 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* 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& 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(this)); + clientCbs.add(IInterface::asBinder(session), clients.valueFor(handle)); +#else + status_t ret = session->asBinder()->linkToDeath(sp(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 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 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& who) +{ + ALOGD("Entering %s", __PRETTY_FUNCTION__); + + sp sp = who.promote(); + ClientCb *cb = clientCbs.valueFor(sp); + + if (cb && cb->cb != NULL) { + cb->cb(cb->context); + free(cb); + clientCbs.removeItem(sp); + } + + unregisterSession(); +} + +sp DecodingClient::decoding_service = NULL; + +DecodingClient::DecodingClient() +{ + ALOGD("%s", __PRETTY_FUNCTION__); + + ProcessState::self()->startThreadPool(); +} + +DecodingClient::~DecodingClient() +{ + ALOGD("%s", __PRETTY_FUNCTION__); +} + +sp& DecodingClient::service_instance() +{ + ALOGD("%s", __PRETTY_FUNCTION__); + // TODO: Add a mutex here + if (decoding_service == NULL) + { + ALOGD("Creating a new static BpDecodingService instance"); + sp service_manager = defaultServiceManager(); + sp service = service_manager->getService( + String16(IDecodingService::exported_service_name())); + decoding_service = new BpDecodingService(service); + } + + return decoding_service; +} + +status_t DecodingClient::getIGraphicBufferConsumer(sp* gbc) +{ + ALOGD("Entering %s", __PRETTY_FUNCTION__); + return service_instance()->getIGraphicBufferConsumer(gbc); +} + +// IDecodingServiceSession + +BpDecodingServiceSession::BpDecodingServiceSession(const sp& impl) + : BpInterface(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 diff --git a/compat/media/decoding_service_priv.h b/compat/media/decoding_service_priv.h new file mode 100644 index 000000000..bf7cfb351 --- /dev/null +++ b/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 + */ + +#ifndef DECODING_SERVICE_PRIV_H_ +#define DECODING_SERVICE_PRIV_H_ + +#include "surface_texture_client_hybris_priv.h" + +#include +#include + +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 +{ +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 +{ +public: + BpDecodingServiceSession(const sp& 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* gbc) = 0; + virtual status_t getIGraphicBufferProducer(sp* gbp) = 0; + virtual status_t registerSession(const sp& session, uint32_t handle) = 0; + virtual status_t unregisterSession() = 0; +}; + +class BnDecodingService: public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +class BpDecodingService: public BpInterface +{ +public: + BpDecodingService(const sp& impl) + : BpInterface(impl) + { + ALOGD("Entering %s", __PRETTY_FUNCTION__); + } + + virtual status_t getIGraphicBufferConsumer(sp* gbc); + virtual status_t getIGraphicBufferProducer(sp* gbp); + virtual status_t registerSession(const sp& 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& service_instance(); + + virtual void setDecodingClientDeathCb(DecodingClientDeathCbHybris cb, uint32_t handle, void* context); + + // IDecodingService interface: + virtual status_t getIGraphicBufferConsumer(sp* gbc); + virtual status_t getIGraphicBufferProducer(sp* gbp); + + virtual status_t registerSession(const sp& session, uint32_t handle); + virtual status_t unregisterSession(); + + /** Get notified when the Binder connection to the client dies **/ + virtual void binderDied(const wp& who); + +protected: + virtual void createBufferQueue(); + +private: + static sp decoding_service; +#if ANDROID_VERSION_MAJOR>=5 + sp producer; + sp consumer; +#else + sp buffer_queue; +#endif + sp session; + DecodingClientDeathCbHybris client_death_cb; + void *client_death_context; + KeyedVector< uint32_t, ClientCb* > clients; + KeyedVector< sp, ClientCb* > clientCbs; +}; + +class DecodingClient +{ +public: + DecodingClient(); + virtual ~DecodingClient(); + + static sp& service_instance(); + + virtual status_t getIGraphicBufferConsumer(sp* gbc); + +private: + static sp decoding_service; +}; + +struct IGBCWrapper +{ + IGBCWrapper(const sp& igbc) + { + consumer = igbc; + } + + sp consumer; +}; + +struct IGBPWrapper +{ + IGBPWrapper(const sp& igbp) + { + producer = igbp; + } + + sp producer; +}; + +struct GLConsumerWrapper +{ + GLConsumerWrapper(const sp<_GLConsumerHybris>& gl_consumer) + { + consumer = gl_consumer; + } + + sp<_GLConsumerHybris> consumer; +}; + +struct DSSessionWrapper +{ + DSSessionWrapper(const sp& session) + { + ALOGD("Entering %s", __PRETTY_FUNCTION__); + this->session = session; + } + + ~DSSessionWrapper() + { + ALOGD("Entering %s", __PRETTY_FUNCTION__); + } + + sp session; +}; + +}; // namespace android + +#endif diff --git a/compat/media/direct_media_test.cpp b/compat/media/direct_media_test.cpp new file mode 100644 index 000000000..d5dd6ab50 --- /dev/null +++ b/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 + * Ricardo Salveti de Araujo + */ + +#include +#include "direct_media_test.h" + +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +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, ¶ms); + + 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 \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; +} diff --git a/compat/media/direct_media_test.h b/compat/media/direct_media_test.h new file mode 100644 index 000000000..5e0546e67 --- /dev/null +++ b/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 + */ + +#ifndef DIRECT_MEDIA_TEST_H_ +#define DIRECT_MEDIA_TEST_H_ + +#include +#include +#include + +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 diff --git a/compat/media/media_buffer_layer.cpp b/compat/media/media_buffer_layer.cpp new file mode 100644 index 000000000..c241ba490 --- /dev/null +++ b/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 + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "MediaCompatibilityLayer" + +#include + +#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(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(buffer); +} + +MediaABufferPrivate::MediaABufferPrivate() +{ +} + +MediaABufferPrivate::MediaABufferPrivate(android::sp 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; +} diff --git a/compat/media/media_buffer_priv.h b/compat/media/media_buffer_priv.h new file mode 100644 index 000000000..c08fcf8f4 --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_BUFFER_PRIV_H_ +#define MEDIA_BUFFER_PRIV_H_ + +#include + +#include + +#include + +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 buffer); + +public: + android::sp buffer; +}; + +#endif diff --git a/compat/media/media_codec_layer.cpp b/compat/media/media_codec_layer.cpp new file mode 100644 index 000000000..98e0da356 --- /dev/null +++ b/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 + */ + +// Uncomment to enable verbose debug output +#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "MediaCodecLayer" + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#if ANDROID_VERSION_MAJOR<=5 +#include +#endif + +#include +#include + +#include +#include +#include +#include + +#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 &msg) { } + +public: + sp media_codec; + sp looper; + + Vector > input_buffers; + Vector > output_buffers; + List available_output_buffer_infos; + Mutex mtx_output_buffer_infos; + List 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 consumer; + decoding_client_instance().getIGraphicBufferConsumer(&consumer); + IGBCWrapper *wrapper = new IGBCWrapper(consumer); + return wrapper; +} + +IGBPWrapperHybris decoding_service_get_igraphicbufferproducer() +{ + REPORT_FUNCTION(); + + sp service_manager = defaultServiceManager(); + sp service = service_manager->getService( + String16(IDecodingService::exported_service_name())); + + sp producer; + DecodingClient::service_instance()->getIGraphicBufferProducer(&producer); + IGBPWrapper *wrapper = new IGBPWrapper(producer); + + return wrapper; +} + +DSSessionWrapperHybris decoding_service_create_session(uint32_t handle) +{ + REPORT_FUNCTION(); + + sp service_manager = defaultServiceManager(); + sp service = service_manager->getService( + String16(IDecodingService::exported_service_name())); + + // Create a new decoding service session + sp 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 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 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 = static_cast(nativeWindow); +#else + sp surfaceTextureClient = static_cast(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 > input_bufs[1]; + err = d->media_codec->getInputBuffers(&input_bufs[0]); + CHECK_EQ(err, static_cast(OK)); + + for (size_t i=0; i<2; ++i) + { + const sp &srcBuffer = format_priv->csd; + + size_t index = 0; + err = d->media_codec->dequeueInputBuffer(&index, -1ll); + CHECK_EQ(err, static_cast(OK)); + + const sp &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(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 > 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 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; +} diff --git a/compat/media/media_codec_list.cpp b/compat/media/media_codec_list.cpp new file mode 100644 index 000000000..f47562d7e --- /dev/null +++ b/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 + */ + +// Uncomment to enable verbose debug output +#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "MediaCodecList" + +#include + +#include +#include + +#include +#include + +#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 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 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 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=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 profile_levels; +#else + Vector profile_levels; +#endif + Vector 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 profile_levels; +#else + Vector profile_levels; +#endif + Vector 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 profile_levels; +#else + Vector profile_levels; +#endif + Vector 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 + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "MediaCompatibilityLayer" + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#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 getFormat(); + android::status_t read(android::MediaBuffer **buffer, const android::MediaSource::ReadOptions *options = NULL); + android::status_t pause(); + + android::sp 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(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 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(&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 &msg); + +public: + void *context; + unsigned int refcount; + android::sp looper; + android::sp codec; + android::sp input_surface; + android::sp source; +}; + +MediaCodecSourcePrivate* MediaCodecSourcePrivate::toPrivate(MediaCodecSourceWrapper *source) +{ + if (!source) + return NULL; + + return static_cast(source); +} + +MediaCodecSourcePrivate::MediaCodecSourcePrivate(void *context) : + context(context), + refcount(1) +{ + REPORT_FUNCTION(); +} + +MediaCodecSourcePrivate::~MediaCodecSourcePrivate() +{ + REPORT_FUNCTION(); +} + +void MediaCodecSourcePrivate::onMessageReceived(const android::sp &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(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; +} diff --git a/compat/media/media_compatibility_layer.cpp b/compat/media/media_compatibility_layer.cpp new file mode 100644 index 000000000..82c00c366 --- /dev/null +++ b/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 + * Ricardo Salveti de Araujo + */ + +// Uncomment to enable verbose debug output +#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "MediaCompatibilityLayer" + +#include + +#include +#include + +#include + +#include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +#include +#else +#include +#endif + +#include +#include + +#include + +#include + +#include + +#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__) + +namespace android +{ +NativeBufferAlloc::NativeBufferAlloc() { +} + +NativeBufferAlloc::~NativeBufferAlloc() { +} + +sp NativeBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, + PixelFormat format, uint32_t usage, status_t* error) { + sp 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 bq, const android::sp &surfaceTexture) +#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + android::status_t setVideoSurfaceTexture(const android::sp &surfaceTexture) +#else + android::status_t setVideoSurfaceTexture(android::sp bq, const android::sp &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 texture; +#else + android::sp texture; +#endif + android::sp media_player_listener; + android::sp 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 native_alloc( + new android::NativeBufferAlloc() + ); + +#if ANDROID_VERSION_MAJOR>=5 + android::sp producer; + android::sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); +#else + android::sp 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( + new android::GLConsumer( +#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + mp->setVideoSurfaceTexture(android::sp( + new android::SurfaceTexture( +#else + mp->setVideoSurfaceTexture(buffer_queue, android::sp( + 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); +} diff --git a/compat/media/media_core.cpp b/compat/media/media_core.cpp new file mode 100644 index 000000000..a1e103454 --- /dev/null +++ b/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 + */ + +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; +} diff --git a/compat/media/media_format_layer.cpp b/compat/media/media_format_layer.cpp new file mode 100644 index 000000000..5bbcb7fbb --- /dev/null +++ b/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 + */ + +// Uncomment to enable verbose debug output +#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "MediaFormatLayer" + +#include +#include "media_format_layer_priv.h" + +#include + +#include + +#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(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; +} diff --git a/compat/media/media_format_layer_priv.cpp b/compat/media/media_format_layer_priv.cpp new file mode 100644 index 000000000..70a4507ad --- /dev/null +++ b/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 + */ + +#include +#include + +#include + +#include + +#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 diff --git a/compat/media/media_format_layer_priv.h b/compat/media/media_format_layer_priv.h new file mode 100644 index 000000000..d06faf58f --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_FORMAT_LAYER_PRIV_H_ +#define MEDIA_FORMAT_LAYER_PRIV_H_ + +#include +#include + +#include +#include + +#include + +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 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_ diff --git a/compat/media/media_message_layer.cpp b/compat/media/media_message_layer.cpp new file mode 100644 index 000000000..a50821791 --- /dev/null +++ b/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 + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "MediaCompatibilityLayer" + +#include + +#include "media_message_priv.h" + +MediaMessagePrivate* MediaMessagePrivate::toPrivate(MediaMessageWrapper *msg) +{ + if (!msg) + return NULL; + + return static_cast(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; +} diff --git a/compat/media/media_message_priv.h b/compat/media/media_message_priv.h new file mode 100644 index 000000000..546273058 --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_MESSAGE_PRIV_H_ +#define MEDIA_MESSAGE_PRIV_H_ + +#include + +#include + +struct MediaMessagePrivate +{ +public: + static MediaMessagePrivate* toPrivate(MediaMessageWrapper *msg); + + explicit MediaMessagePrivate(); + virtual ~MediaMessagePrivate(); + + android::sp msg; +}; + +#endif diff --git a/compat/media/media_meta_data_layer.cpp b/compat/media/media_meta_data_layer.cpp new file mode 100644 index 000000000..91149e2a5 --- /dev/null +++ b/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 + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "MediaCompatibilityLayer" + +#include + +#include "media_meta_data_priv.h" + +MediaMetaDataPrivate* MediaMetaDataPrivate::toPrivate(MediaMetaDataWrapper *md) +{ + if (!md) + return NULL; + + return static_cast(md); +} + +MediaMetaDataPrivate::MediaMetaDataPrivate() : + data(new android::MetaData) +{ +} + +MediaMetaDataPrivate::MediaMetaDataPrivate(const android::sp &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; +} diff --git a/compat/media/media_meta_data_priv.h b/compat/media/media_meta_data_priv.h new file mode 100644 index 000000000..cc9e720ea --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_META_DATA_PRIV_H_ +#define MEDIA_META_DATA_PRIV_H_ + +#include + +struct MediaMetaDataPrivate +{ +public: + static MediaMetaDataPrivate* toPrivate(MediaMetaDataWrapper *md); + + MediaMetaDataPrivate(); + MediaMetaDataPrivate(const android::sp &md); + ~MediaMetaDataPrivate(); + + android::sp data; +}; + +#endif diff --git a/compat/media/media_recorder.cpp b/compat/media/media_recorder.cpp new file mode 100644 index 000000000..8db16a3cc --- /dev/null +++ b/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 +#include +#include +#include +#include +#include // for MEDIA_ERROR_SERVER_DIED +#include + +namespace android { + +status_t MediaRecorder::setCamera(const sp& camera, const sp& 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& 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 object to hook up to ANativeWindow. +sp 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 sm = defaultServiceManager(); + sp 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(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& 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 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 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 diff --git a/compat/media/media_recorder.h b/compat/media/media_recorder.h new file mode 100644 index 000000000..d9c3d6045 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include + +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& camera, const sp& proxy); + status_t setPreviewSurface(const sp& 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& 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 querySurfaceMediaSourceFromMediaServer(); + +private: + void doCleanUp(); + status_t doReset(); + + sp mMediaRecorder; + sp mListener; + sp mMediaRecorderFactory; + + // Reference to IGraphicBufferProducer + // for encoding GL Frames. That is useful only when the + // video source is set to VIDEO_SOURCE_GRALLOC_BUFFER + sp 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 diff --git a/compat/media/media_recorder_client.cpp b/compat/media/media_recorder_client.cpp new file mode 100644 index 000000000..b781dea16 --- /dev/null +++ b/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 + */ + +#include "media_recorder_client.h" + +#include +#include + +#define LOG_NDEBUG 0 +#define LOG_TAG "MediaRecorderClient" + +#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__) + +using namespace android; + +MediaRecorderClient::MediaRecorderClient() +{ + REPORT_FUNCTION(); + + sp service_manager = defaultServiceManager(); + sp 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& camera, + const sp& 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& 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& 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& 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& args) const +{ + REPORT_FUNCTION(); + if (recorder != NULL) { + return recorder->dump(fd, args); + } + return android::OK; +} + +sp MediaRecorderClient::querySurfaceMediaSource() +{ + REPORT_FUNCTION(); + Mutex::Autolock lock(recorder_lock); + if (recorder == NULL) { + ALOGE("recorder is not initialized"); + return NULL; + } + return recorder->querySurfaceMediaSource(); +} diff --git a/compat/media/media_recorder_client.h b/compat/media/media_recorder_client.h new file mode 100644 index 000000000..6ee40dce7 --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_RECORDER_CLIENT_H_ +#define MEDIA_RECORDER_CLIENT_H_ + +#include +#include + +#include "media_recorder_observer.h" + +#include + +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& camera, + const sp& proxy); + virtual status_t setPreviewSurface(const sp& 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& 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& 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& args) const; + virtual sp querySurfaceMediaSource(); + +private: + sp media_recorder_observer; + MediaRecorderBase *recorder; + Mutex recorder_lock; +}; + +} + +#endif diff --git a/compat/media/media_recorder_factory.cpp b/compat/media/media_recorder_factory.cpp new file mode 100644 index 000000000..e4b6a5fae --- /dev/null +++ b/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 + */ + +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "MediaRecorderFactory" + +#include "media_recorder_factory.h" +#include "media_recorder_client.h" +#include + +#include +#include +#include + +#include +#include + +#define REPORT_FUNCTION() ALOGV("%s \n", __PRETTY_FUNCTION__) + +namespace android { + +enum { + CREATE_MEDIA_RECORDER = IBinder::FIRST_CALL_TRANSACTION, +}; + +class BpMediaRecorderFactory: public BpInterface +{ +public: + BpMediaRecorderFactory(const sp& impl) + : BpInterface(impl) + { + } + + virtual sp createMediaRecorder() + { + Parcel data, reply; + data.writeInterfaceToken(IMediaRecorderFactory::getInterfaceDescriptor()); + remote()->transact(CREATE_MEDIA_RECORDER, data, &reply); + return interface_cast(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 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::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 MediaRecorderFactory::createMediaRecorder() +{ + REPORT_FUNCTION(); + sp recorder = new MediaRecorderClient(); + return recorder; +} + +/*! + * \brief Get a reference to the MediaRecorderFactory singleton instance + * \return The MediaRecorderFactory singleton instance + */ +sp& 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 diff --git a/compat/media/media_recorder_factory.h b/compat/media/media_recorder_factory.h new file mode 100644 index 000000000..88634d93f --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_RECORDER_FACTORY_H_ +#define MEDIA_RECORDER_FACTORY_H_ + +#include + +#include +#include + +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 createMediaRecorder() = 0; +}; + +// ---------------------------------------------------------------------------- + +class BnMediaRecorderFactory: public BnInterface +{ +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 createMediaRecorder(); +private: + static sp& factory_instance(); + + static sp media_recorder_factory; + static Mutex s_lock; +}; + +} + +#endif diff --git a/compat/media/media_recorder_layer.cpp b/compat/media/media_recorder_layer.cpp new file mode 100644 index 000000000..b7354caa5 --- /dev/null +++ b/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 + * Guenter Schwann + * Ricardo Salveti de Araujo + */ + +#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "MediaRecorderCompatibilityLayer" + +#include "media_recorder.h" + +#include +#include + +#include +#include + +#include +#include +#include + +#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 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(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(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(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(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(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(); +} diff --git a/compat/media/media_recorder_observer.cpp b/compat/media/media_recorder_observer.cpp new file mode 100644 index 000000000..da53baae3 --- /dev/null +++ b/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 + */ + +// Uncomment to enabe verbose debug output +//#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "MediaRecorderObserver" + +#include "media_recorder_observer.h" + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +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); +} diff --git a/compat/media/media_recorder_observer.h b/compat/media/media_recorder_observer.h new file mode 100644 index 000000000..6a6c9889c --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_RECORDER_OBSERVER_H_ +#define MEDIA_RECORDER_OBSERVER_H_ + +#include +#include + +#include + +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 +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +class BpMediaRecorderObserver: public BpInterface +{ +public: + BpMediaRecorderObserver(const sp& impl) + : BpInterface(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 diff --git a/compat/media/surface_texture_client_hybris.cpp b/compat/media/surface_texture_client_hybris.cpp new file mode 100644 index 000000000..a3af4f27b --- /dev/null +++ b/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 + */ + +// Uncomment to enable verbose debug output +#define LOG_NDEBUG 0 + +#undef LOG_TAG +#define LOG_TAG "SurfaceTextureClientHybris" + +#include +#include "surface_texture_client_hybris_priv.h" +#include "decoding_service_priv.h" + +#include +#include +#include +#include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +#include +#endif +#include +#include + +#include +#include + +#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 &st) + : Surface::Surface(st, true), + refcount(1), + ready(false) +{ + REPORT_FUNCTION() +} +#elif ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR>=4 +_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp &bq) + : Surface::Surface(bq, true), + refcount(1), + ready(false) +{ + REPORT_FUNCTION() +} + +_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp &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 &st) + : SurfaceTextureClient::SurfaceTextureClient(st), +#else +_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const sp &st) + : Surface::Surface(st, false), +#endif + refcount(1), + ready(false) +{ + REPORT_FUNCTION() +} +#endif + +_SurfaceTextureClientHybris::_SurfaceTextureClientHybris(const android::sp &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& surface_texture) +{ + SurfaceTextureClient::setISurfaceTexture(surface_texture); +#else +void _SurfaceTextureClientHybris::setISurfaceTexture(const sp& 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 &surface_texture) +#else +static inline void set_surface(_SurfaceTextureClientHybris *stch, const sp &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 producer; + sp 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 native_alloc(new NativeBufferAlloc()); + + sp buffer_queue(new BufferQueue(false, NULL, native_alloc)); + _SurfaceTextureClientHybris *stch(new _SurfaceTextureClientHybris); +#else + sp 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(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(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(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(wrapper); + sp<_GLConsumerHybris> glc_hybris = static_cast<_GLConsumerHybris*>(glc_wrapper->consumer.get()); + glc_hybris->getTransformMatrix(static_cast(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(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(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(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(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 = static_cast(native_window); +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 + s->setISurfaceTexture(surface->getSurfaceTexture()); +#else + s->setISurfaceTexture(surface->getIGraphicBufferProducer()); +#endif +} diff --git a/compat/media/surface_texture_client_hybris_priv.h b/compat/media/surface_texture_client_hybris_priv.h new file mode 100644 index 000000000..e168bf89c --- /dev/null +++ b/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 + */ + +#ifndef SURFACE_TEXTURE_CLIENT_HYBRIS_PRIV_H +#define SURFACE_TEXTURE_CLIENT_HYBRIS_PRIV_H + +#include "hybris/media/surface_texture_client_hybris.h" + +#include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 +#include +#else +#include +#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 &st); +#else + _SurfaceTextureClientHybris(const android::sp &st); + _SurfaceTextureClientHybris(const android::sp &st, + bool producerIsControlledByApp); + _SurfaceTextureClientHybris(const android::sp &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& surface_texture); +#else + void setISurfaceTexture(const android::sp& 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 surface_texture; +#else + android::sp 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& 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 diff --git a/compat/surface_flinger/Android.mk b/compat/surface_flinger/Android.mk new file mode 100644 index 000000000..1ef776422 --- /dev/null +++ b/compat/surface_flinger/Android.mk @@ -0,0 +1,50 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../Android.common.mk + +HYBRIS_PATH := $(LOCAL_PATH)/../../hybris + +LOCAL_SRC_FILES:= \ + surface_flinger_compatibility_layer.cpp + +LOCAL_MODULE:= libsf_compat_layer +LOCAL_MODULE_TAGS := optional + +LOCAL_C_INCLUDES := \ + $(HYBRIS_PATH)/include + +LOCAL_SHARED_LIBRARIES := \ + libui \ + libutils \ + libgui \ + libEGL \ + libGLESv2 + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +HYBRIS_PATH := $(LOCAL_PATH)/../../hybris + +LOCAL_SRC_FILES:= \ + direct_sf_test.cpp + +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 + +LOCAL_SHARED_LIBRARIES := \ + libui \ + libutils \ + libEGL \ + libGLESv2 \ + libsf_compat_layer + +include $(BUILD_EXECUTABLE) diff --git a/compat/surface_flinger/surface_flinger_compatibility_layer.cpp b/compat/surface_flinger/surface_flinger_compatibility_layer.cpp new file mode 100644 index 000000000..6a32f2239 --- /dev/null +++ b/compat/surface_flinger/surface_flinger_compatibility_layer.cpp @@ -0,0 +1,366 @@ +/* + * 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: Thomas Voss + * Ricardo Salveti de Araujo + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#if ANDROID_VERSION_MAJOR>=5 + #include +#endif + +#include +#include + +namespace +{ +void report_failed_to_allocate_surface_flinger_composer_client_on_creation() +{ + printf("Problem allocating an object of type SurfaceComposerClient during client creation"); +} + +void report_failed_to_get_egl_default_display_on_creation() +{ + printf("Problem accessing default egl display during client creation"); +} + +void report_failed_to_initialize_egl_on_creation() +{ + printf("Problem initializing egl during client creation"); +} + +void report_failed_to_choose_egl_config_on_creation() +{ + printf("Problem choosing egl config on creation"); +} + +void report_surface_control_is_null_during_creation() +{ + printf("Could not acquire surface control object during surface creation"); +} + +void report_surface_is_null_during_creation() +{ + printf("Could not acquire surface from surface control during surface creation"); +} +} + +void sf_blank(size_t display_id) +{ + android::sp display; + + if (display_id == 0) { + display = android::SurfaceComposerClient::getBuiltInDisplay( + android::ISurfaceComposer::eDisplayIdMain); + } else if (display_id == 1) { + display = android::SurfaceComposerClient::getBuiltInDisplay( + android::ISurfaceComposer::eDisplayIdHdmi); + } else { + fprintf(stderr, "Warning: sf_blank invalid display_id (0 || 1)\n"); + 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) +{ + android::sp display; + + if (display_id == 0) { + display = android::SurfaceComposerClient::getBuiltInDisplay( + android::ISurfaceComposer::eDisplayIdMain); + } else if (display_id == 1) { + display = android::SurfaceComposerClient::getBuiltInDisplay( + android::ISurfaceComposer::eDisplayIdHdmi); + } else { + fprintf(stderr, "Warning: sf_unblank invalid display_id (0 || 1)\n"); + 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) +{ + android::sp display; + + if (display_id == 0) { + display = android::SurfaceComposerClient::getBuiltInDisplay( + android::ISurfaceComposer::eDisplayIdMain); + } else if (display_id == 1) { + display = android::SurfaceComposerClient::getBuiltInDisplay( + android::ISurfaceComposer::eDisplayIdHdmi); + } else { + fprintf(stderr, "Warning: sf_get_display_width invalid display_id (0 || 1)\n"); + return -1; + } + + android::DisplayInfo info; + android::SurfaceComposerClient::getDisplayInfo(display, &info); + return info.w; +} + +size_t sf_get_display_height(size_t display_id) +{ + android::sp display; + + if (display_id == 0) { + display = android::SurfaceComposerClient::getBuiltInDisplay( + android::ISurfaceComposer::eDisplayIdMain); + } else if (display_id == 1) { + display = android::SurfaceComposerClient::getBuiltInDisplay( + android::ISurfaceComposer::eDisplayIdHdmi); + } else { + fprintf(stderr, "Warning: sf_get_display_height invalid display_id (0 || 1)\n"); + return -1; + } + + android::DisplayInfo info; + android::SurfaceComposerClient::getDisplayInfo(display, &info); + return info.h; +} + +SfClient* sf_client_create_full(bool egl_support) +{ + SfClient* client = new SfClient(); + + client->client = new android::SurfaceComposerClient(); + if (client->client == NULL) { + report_failed_to_allocate_surface_flinger_composer_client_on_creation(); + delete client; + return NULL; + } + + client->egl_support = egl_support; + if (egl_support) { + client->egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (client->egl_display == EGL_NO_DISPLAY) { + report_failed_to_get_egl_default_display_on_creation(); + delete client; + return NULL; + } + + int major, minor; + int rc = eglInitialize(client->egl_display, &major, &minor); + if (rc == EGL_FALSE) { + report_failed_to_initialize_egl_on_creation(); + delete client; + return NULL; + } + + EGLint attribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE + }; + + int n; + if (eglChooseConfig(client->egl_display, + attribs, + &client->egl_config, 1, + &n) == EGL_FALSE) { + report_failed_to_choose_egl_config_on_creation(); + delete client; + return NULL; + } + + EGLint context_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + client->egl_context = eglCreateContext( + client->egl_display, + client->egl_config, + EGL_NO_CONTEXT, + context_attribs); + } + + return client; +} + +SfClient* sf_client_create() +{ + return sf_client_create_full(true); +} + +EGLDisplay sf_client_get_egl_display(SfClient* client) +{ + assert(client); + + if (client->egl_support) + return client->egl_display; + else { + fprintf(stderr, "Warning: sf_client_get_egl_display not supported, EGL " + "support disabled\n"); + return NULL; + } +} + +EGLConfig sf_client_get_egl_config(SfClient* client) +{ + assert(client); + + if (client->egl_support) + return client->egl_config; + else { + fprintf(stderr, "Warning: sf_client_get_egl_config not supported, EGL " + "support disabled\n"); + return NULL; + } +} + +void sf_client_begin_transaction(SfClient* client) +{ + assert(client); + client->client->openGlobalTransaction(); +} + +void sf_client_end_transaction(SfClient* client) +{ + assert(client); + client->client->closeGlobalTransaction(); +} + +SfSurface* sf_surface_create(SfClient* client, SfSurfaceCreationParameters* params) +{ + assert(client); + assert(params); + + SfSurface* surface = new SfSurface(); + surface->client = client; + surface->surface_control = surface->client->client->createSurface( + android::String8(params->name), + params->w, + params->h, + android::PIXEL_FORMAT_RGBA_8888, + 0x300); + + if (surface->surface_control == NULL) { + report_surface_control_is_null_during_creation(); + delete(surface); + return NULL; + } + + surface->surface = surface->surface_control->getSurface(); + + if (surface->surface == NULL) { + report_surface_is_null_during_creation(); + delete(surface); + return NULL; + } + + sf_client_begin_transaction(client); + { + surface->surface_control->setPosition(params->x, params->y); + surface->surface_control->setLayer(params->layer); + surface->surface_control->setAlpha(params->alpha); + } + sf_client_end_transaction(client); + + if (params->create_egl_window_surface) { + if (client->egl_support) { + android::sp anw(surface->surface); + surface->egl_surface = eglCreateWindowSurface( + surface->client->egl_display, + surface->client->egl_config, + anw.get(), + NULL); + } else + fprintf(stderr, "Warning: params->create_egl_window_surface not " + "supported, EGL support disabled\n"); + } + + return surface; +} + +EGLSurface sf_surface_get_egl_surface(SfSurface* surface) +{ + assert(surface); + + if (surface->client->egl_support) + return surface->egl_surface; + else { + fprintf(stderr, "Warning: sf_surface_get_egl_surface not supported, " + "EGL support disabled\n"); + return NULL; + } +} + +EGLNativeWindowType sf_surface_get_egl_native_window(SfSurface* surface) +{ + assert(surface); + return surface->surface.get(); +} + +void sf_surface_make_current(SfSurface* surface) +{ + assert(surface); + + if (surface->client->egl_support) { + eglMakeCurrent( + surface->client->egl_display, + surface->egl_surface, + surface->egl_surface, + surface->client->egl_context); + } else { + fprintf(stderr, "Warning: sf_surface_make_current not supported, EGL " + "support disabled\n"); + } +} + +void sf_surface_move_to(SfSurface* surface, int x, int y) +{ + assert(surface); + surface->surface_control->setPosition(x, y); +} + +void sf_surface_set_size(SfSurface* surface, int w, int h) +{ + assert(surface); + surface->surface_control->setSize(w, h); +} + +void sf_surface_set_layer(SfSurface* surface, int layer) +{ + assert(surface); + surface->surface_control->setLayer(layer); +} + +void sf_surface_set_alpha(SfSurface* surface, float alpha) +{ + assert(surface); + surface->surface_control->setAlpha(alpha); +} diff --git a/compat/ui/Android.mk b/compat/ui/Android.mk new file mode 100644 index 000000000..5cfa6c27c --- /dev/null +++ b/compat/ui/Android.mk @@ -0,0 +1,26 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../Android.common.mk + +HYBRIS_PATH := $(LOCAL_PATH)/../../hybris + +LOCAL_SRC_FILES:= \ + ui_compatibility_layer.cpp + +LOCAL_MODULE:= libui_compat_layer +LOCAL_MODULE_TAGS := optional + +LOCAL_C_INCLUDES := \ + $(HYBRIS_PATH)/include \ + frameworks/native/include + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libbinder \ + libhardware \ + libui + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) diff --git a/compat/ui/ui_compatibility_layer.cpp b/compat/ui/ui_compatibility_layer.cpp new file mode 100644 index 000000000..c015e361b --- /dev/null +++ b/compat/ui/ui_compatibility_layer.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2013 Simon Busch + * + * 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 +#include + +#include +#include +#include + +#include + +struct graphic_buffer +{ + android::GraphicBuffer *self; +}; + +struct graphic_buffer* graphic_buffer_new(void) +{ + struct graphic_buffer *buffer = NULL; + + buffer = (struct graphic_buffer*) malloc(sizeof(struct graphic_buffer)); + if (!buffer) + return NULL; + + buffer->self = new android::GraphicBuffer(); + + return buffer; +} + +struct graphic_buffer* graphic_buffer_new_sized(uint32_t w, uint32_t h, + int32_t format, uint32_t usage) +{ + struct graphic_buffer *buffer = NULL; + + buffer = (struct graphic_buffer*) malloc(sizeof(struct graphic_buffer)); + if (!buffer) + return NULL; + + buffer->self = new android::GraphicBuffer(w, h, format, usage); + + return buffer; +} + +struct graphic_buffer* graphic_buffer_new_existing(uint32_t w, uint32_t h, + int32_t format, uint32_t usage, + uint32_t stride, void *handle, + bool keepOwnership) +{ + struct graphic_buffer *buffer = NULL; + + buffer = (struct graphic_buffer*) malloc(sizeof(struct graphic_buffer)); + if (!buffer) + return NULL; + + buffer->self = new android::GraphicBuffer(w, h, format, usage, stride, (native_handle_t*) handle, keepOwnership); + + return buffer; + +} + +void graphic_buffer_free(struct graphic_buffer *buffer) +{ + if (!buffer) + return; + + free(buffer); +} + +uint32_t graphic_buffer_get_width(struct graphic_buffer *buffer) +{ + return buffer->self->getWidth(); +} + +uint32_t graphic_buffer_get_height(struct graphic_buffer *buffer) +{ + return buffer->self->getHeight(); +} + +uint32_t graphic_buffer_get_stride(struct graphic_buffer *buffer) +{ + return buffer->self->getStride(); +} + +uint32_t graphic_buffer_get_usage(struct graphic_buffer *buffer) +{ + return buffer->self->getUsage(); +} + +int32_t graphic_buffer_get_pixel_format(struct graphic_buffer *buffer) +{ + return buffer->self->getPixelFormat(); +} + +uint32_t graphic_buffer_reallocate(struct graphic_buffer *buffer, uint32_t w, + uint32_t h, int32_t f, uint32_t usage) +{ + return buffer->self->reallocate(w, h, f, usage); +} + +uint32_t graphic_buffer_lock(struct graphic_buffer *buffer, uint32_t usage, void **vaddr) +{ + return buffer->self->lock(usage, vaddr); +} + +uint32_t graphic_buffer_unlock(struct graphic_buffer *buffer) +{ + return buffer->self->unlock(); +} + +void* graphic_buffer_get_native_buffer(struct graphic_buffer *buffer) +{ + 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); +} + +int graphic_buffer_get_index(struct graphic_buffer *buffer) +{ + return buffer->self->getIndex(); +} +#endif + +int graphic_buffer_init_check(struct graphic_buffer *buffer) +{ + return buffer->self->initCheck(); +} diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 000000000..804ea87f3 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,973 @@ +libhybris (0.1.0+git20151016+6d424c9-0ubuntu23) yakkety; urgency=medium + + [ You-Sheng Yang ] + * build: fix warnings due to arm32/arm64 types size differences + * build: include config.h first + * hooks: fix scandir/scandirat hooks prototypes + * hooks: fix arm64 shared pthread ptr implementation + * hooks: use pthread_attr_{get,set}stack when available + + [ Iain Lane ] + * hooks:c: Don't pass builtin functions. + + [ You-Sheng Yang ] + * compat: always build binaries for both arch + * build: fix misc warnings + * hooks: fix bionic FILE struct size on arm64 + * hooks: add readdir64, readdir64_r + * hooks: fix getmntent, getmntent_r + * Revert "hooks: use pthread_attr_{get,set}stack when available" + + -- Simon Fels Thu, 18 Aug 2016 10:35:52 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu22) yakkety; urgency=medium + + [ You-Sheng Yang ] + * linker: disable linker probing when unavailable + * linker: remove /system/lib prefix from lib paths + * configure: use lib64 for DEFAULT_HYBRIS_LD_LIBRARY_PATH on arm64 + * compat: build arm64 flavor when available + + -- Simon Fels Fri, 05 Aug 2016 18:46:06 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu21) yakkety; urgency=medium + + [ Alfonso Sanchez-Beato ] + * compat: media: add bool macro definition + + -- Simon Fels Wed, 13 Jul 2016 08:35:49 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu20) yakkety; urgency=medium + + [ Alfonso Sanchez-Beato ] + * hybris: common: remove hooks for signal handling + + [ Simon Fels ] + * hybris: wifi: add new API method to send driver command + + -- Simon Fels Thu, 07 Jul 2016 10:40:38 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu19) yakkety; urgency=medium + + [ Bin Li ] + * hybris: common: Add hooks to support scandir + + [ Simon Fels ] + * hybris: common: remove old and unused gb and ics linkers + * hybris: common: mm: include strlcat/strlcpy to avoid linke time issues + * hybris: common: mm: drop unneeded compile time definitions + + -- Simon Fels Wed, 29 Jun 2016 17:41:10 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu18) yakkety; urgency=medium + + [ Boleslaw Tokarski ] + * [properties] An off-by-one error in prop handling + + [ Gunnar Sletta ] + * [glesv2] Wrap glGetString() and return GL_VERSION == 2.0 + + -- Simon Fels Wed, 22 Jun 2016 13:27:17 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu17) yakkety; urgency=medium + + * Revert "Fix resolving the GLEsv2 functions at link time" + * hybris: common: fine tune dynamic linker load process + * hybris: glesv2: load symbols on demand + * hybris: glesv2: drop redefined symbols + * hybris: glesv2: really drop all unneeded symbols + * hybris: glesv2: revert back to version without using GNU indirect feature + * hybris: common: more fine tuning for runtime linker loading + * hybris: common: use correct property name for device name + * hybris: common: force SDK version 19 for cooler too + * hybris: common: add env variable to override selected SDK version + * hybris: common: use debug log statement rather than plain printf + * hybris: common: rename variable containing hooks for all devices + * hybris: glesv2: don't return anything in functions with void as return type + * hybris: common: enable linker overrides only by configure option + * debian: enable ubuntu linker overrides only for armhf + + -- Simon Fels Tue, 21 Jun 2016 11:58:45 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu16) yakkety; urgency=medium + + * No change release. + + -- Simon Fels Wed, 15 Jun 2016 17:48:02 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu15) yakkety; urgency=medium + + * hybris: mm: use recursive mutex for dlopen/.. locking + * hybris: common: add support for dynamic linker loading at runtime + + -- Simon Fels Wed, 15 Jun 2016 16:55:55 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu14) yakkety; urgency=medium + + [ Ondrej Kubik ] + * Fix Android 6.x build for Android Build System. + + [ Rex Tsai (蔡志展) ] + * Fix MediaCodecSource::Create() API change for Android 6.0.0_r1. + + [ Simon Fels ] + * hybris: introduce experimental configuration feature + * hybris: note used android version in configure summary + * hybris: common: import marshmallow linker + * hybris: common: enable building marshmellow linker + * hybris: common: make marshmellow linker building + * hybris: common: mm: drop support for libs inside zip archives + * hybris: common: mm: get rid of sys/limits.h copy + * hybris: common: mm: disable tls initialization + * hybris: common: mm: disable debuggerd connection + * hybris: common: mm: export android_* dlfcn functions for use from C + * hybris: common: add hybris prefix for our hook processing method + * hybris: common: mm: add symbol hooking functionality + * hybris: common: mm: redirect all linker logs to stdout + * hybris: common: mm: use HYBRIS_LD_DEBUG to enable debug output + * hybris: common: mm: get linker building on arm platforms + * hybris: common: build with c++ support + * hybris: common: mm: further enablement work + * hybris: common: mm: don't memset class instance + * hybris: common: mm: disable linker internal memory mgmt for small objects + * hybris: common: mm: respect hybris specific library paths only + * hybris: common: mm: replace LINKER_DEBUG with TRACE_DEBUG + * hybris: mention experimental configure option in summary + * hybris: common: add missing libs we have to link to + * hybris: common: mm: switch from fprintf to DEBUG + * hybris: common: mm: disable some more code parts we don't use + * tests: add missing pthread to LDADD for test_nfc + * hybris: common: add c'tor to initialize linker logging + * hybris: common: add ability to deliver hooks from the outside + * hybris: common: mm: add missing line ending for error messages + * hybris: common: mm: fix compliation in x86 + * hybris: common: really make hooking work + * hybris: common: make hook handler availble for C++ + * hybris: common: deliver symbol requester through our hooks too + * hybris: egl: don't create surface mapping when creation failed + * hybris: hooks: hook a few more symbols for Android 6 support + * hybris: common: switch hook prefix to _hybris_hook_ + * hybris: common: add tracing support for our hooks + * utils: update load-sym-files gdb command to python3 + * hybris: common: convert addrinfo struct correctly + * hybris: common: respect unsigned nature of size_t + * hybris: common: add tracing for sysconf hook + * hybris: common: add proper copyright header for sysconf implementation + * hybris: common: add more hooks to let string.* bionic tests pass + * hybris: common: add new keys for sysconf + * hybris: common: add a few more necessary hooks + * hybris: common: improve tracing for a few hooks + * hybris: use pthread rather than lpthread to link with pthread lib + * hybris: common: mm: drop old ARCH_FLAGS we don't need + * hybris: common: add hook for strcmp to fail on nullptr + * hybris: common: fix printf format + * hybris: common: add more necessary hooks + * debian: install load_sym_files.py gdb helper script + * debian: enable mm linker by default + * hybris: detect arm64 architecture at configuration time + * hybris: common: mm: use correct names for relocation types + * debian: package libGLESv1_CM.so + + [ Giulio Camuffo ] + * Fix resolving the GLEsv2 functions at link time + + [ Simon Fels ] + * debian: update copyright file + * debian: bump standards version to 3.9.7 + + -- Simon Fels Tue, 14 Jun 2016 09:52:43 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu13) xenial; urgency=medium + + * hybris: common: stub: don't assert but return error + + -- Simon Fels Mon, 09 May 2016 16:09:26 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu12) xenial; urgency=medium + + * debian: split out arch specific configuration flags + + -- Simon Fels Fri, 06 May 2016 09:48:53 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu11) xenial; urgency=medium + + * hybris: common: add stub linker implementation + * debian: split out common parts of the default configuration + * debian: add build support for arm64 + * hybris: add README file stating which architectures are supported + * hybris: autotools want it to be README + + -- Simon Fels Tue, 03 May 2016 17:29:41 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu10) xenial; urgency=medium + + * debian: add missing hybris/common include directory + + -- Simon Fels Thu, 21 Apr 2016 11:06:48 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu9) xenial; urgency=medium + + * hybris/compat: media: wrap android media codec source implementation + * compat: media: only build media codec source support for Android 5.x + * compat: media: introduce API version number + * compat: media: don't put Android 5.x as a requirement for MediaCodecSource + + -- Simon Fels Wed, 13 Apr 2016 11:58:56 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu8) xenial; urgency=medium + + * No change rebuild to cover a new android-headers release which + floating point ABI problems. + + -- Simon Fels Mon, 11 Apr 2016 10:51:55 +0200 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu7) xenial; urgency=medium + + [ Ugo Riboni ] + * Allow setting/clearning the camera metering region + + [ Alex Tu ] + * compat: force modules to be build for 32bit only + + [ Simon Fels ] + * debian: adjust our build depends depending which distro we build for + - With this we select now gcc 4.7 for vivid builds and take what + ever else is default on all other distributions. We need to switch + soon or later away from gcc 4.7 but before we can do that we need + to overcome the still existing ABI issues we get when we build + with something else than gcc 4.7. + + -- Simon Fels Mon, 07 Mar 2016 10:41:54 +0100 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu6) xenial; urgency=medium + + [ Simon Fels ] + * Revert "debian: drop requirement of gcc 4.7" + + [ Franz-Josef ] + * hybris: add hook for freeaddrinfo and getaddrinfo + + -- Simon Fels Fri, 05 Feb 2016 15:23:26 +0100 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu5) xenial; urgency=medium + + * debian: drop requirement of gcc 4.7 + + -- Simon Fels Tue, 26 Jan 2016 12:37:21 +0100 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu4) xenial; urgency=medium + + [ You-Sheng Yang ] + * wifi: fix hardware_legacy/wifi.h not found + * tests: fix test_audio compilation on Android 5 or above + + [ Carsten Munk ] + * Hook getlogin, __sprintf_chk, __snprintf_chk + + [ Simon Fels ] + * hybris: common: dump mutex address + * hybris: common: add ugly workaround for malit-hist-dump thread + * hybris: common: also hook prctl to workaround mali-hist-dump + * hybris: common: also log name when prctl called with PR_SET_NAME + * hybris: common: add exit workaround for mali-hist-dump thread + * hybris: common: be more precise on prctl log messages + * hybris: add configuration option to enable mali related quirks + * hybris: common: hook localtime, gmtime and friends + * debian: enable mali quirks + * hybris: common: hook missing pthread functions + * hybris: common: add further debug statements for symbol hooking + * debian: update changelog + + [ You-Sheng Yang ] + * compat: media: remove wrong BOARD_HAS_MEDIA_PLAYER_PAUSE guard + * compat: media: implement android::IMediaRecorder::resume + + [ Simon Fels ] + * debian: drop files listed twice in .install files + * debian: drop -dbg package as we generate them automatically + + [ You-Sheng Yang ] + * hooks: add pthread_mutex_timedlock + + [ Thomas Voß ] + * Hook pthread_kill such that pthread_t values of 0 do not lead to segfaults. + + [ Simon Fels ] + * debian: update changelog + * debian: correct vcs reference to point to launchpad + + [ You-Sheng Yang ] + * hook: add pthread_condattr_setclock + * hook: skip only symbol names prefixed with "pthread" or "__pthread" + + [ Mikko Harju ] + * [libhybris] Add cache for socket based property lookups. + + [ Simon Fels ] + * hybris: common: add simple macro to check for existing symbols + * debian: drop stripping of not existing package + * Revert "debian: don't package NFC stuff anymore" + * utils: fix binding wrapper macro generator script + * debian: sync changelog up with what is released + * debian: enable property cache for x86 and armhf + * debian: rules: cleanup formatting for autoconf options + + -- Simon Fels Tue, 26 Jan 2016 11:05:14 +0100 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu3) vivid; urgency=medium + + * Various fixes to allow camera access to work in the web browser + * Fix compat layer compilation when API functions are missing on + certain devices in the media player implementation. + * Add initial support for Android 5.x + + -- Simon Fels Thu, 07 Jan 2016 08:07:11 +0100 + +libhybris (0.1.0+git20151016+6d424c9-0ubuntu1) vivid; urgency=medium + + [ Ricardo Salveti de Araujo ] + * New upstream snapshot: + - Rebasing patches and removing the ones that are already available in + upstream + + [ Alex Tu ] + * Fix Build error. + + [ Simon Fels ] + * Merge with upstream and rebased chagnes + + -- Simon Fels Fri, 16 Oct 2015 09:14:11 +0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu39) vivid; urgency=medium + + * linker: adding dl_iterate_phdr for ARM (required by Android 5 blobs) + + -- Ricardo Salveti de Araujo Mon, 06 Apr 2015 20:53:06 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu38) vivid; urgency=medium + + * Reverting switch to CLOCK_MONOTONIC_RAW as that caused a regression + when recording videos with krillin + + -- Ricardo Salveti de Araujo Mon, 16 Mar 2015 15:59:00 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu37) vivid; urgency=medium + + * Backporting fixes from upstream before doing a new rebase: + - sysconf mapping + - New optimization via gnu dispatching: zero call overhead glesv2 + wrapper + - dlsym the symbols in eglGetProcAddress from the glibc libraries + - hooks.c: Switch to CLOCK_MONOTONIC_RAW instead of CLOCK_REALTIME + - hooks.c: fixing typos in function calls + - Fix a missmatch between glibc's addrinfo and bionic's getaddrinfo + + -- Ricardo Salveti de Araujo Thu, 12 Mar 2015 01:16:13 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu36) vivid; urgency=medium + + [ Ugo Riboni ] + * camera: expose the ability to query the supported flash modes + + -- Ricardo Salveti de Araujo Wed, 14 Jan 2015 19:28:56 -0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu35) vivid; urgency=medium + + [ Alfonso Sanchez-Beato ] + * media: thread-protect list output buffer infos list + + [ Mathieu Trudel-Lapierre ] + * wifi: add method to check if compat side is available + + -- Ricardo Salveti de Araujo Mon, 08 Dec 2014 14:28:57 -0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu34) vivid; urgency=medium + + [Florian Boucault] + * camera/compat: added getter/setter for JPEG encoding quality. + + -- Ricardo Salveti de Araujo Tue, 25 Nov 2014 11:12:26 -0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu33) vivid; urgency=medium + + [Yuan-Chen Cheng] + * Use PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP in dlfcn.c for + bionic/linker/dlfcn.cpp use it and needed by certain android bsp. + This is basically a cherry-pick from android upstream. + + -- Ricardo Salveti de Araujo Thu, 20 Nov 2014 19:48:28 -0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu32) vivid; urgency=medium + + [ Alfonso Sanchez-Beato ] + * media: thread-protect release of media buffers + + -- Ricardo Salveti de Araujo Thu, 13 Nov 2014 22:09:31 -0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu31) vivid; urgency=medium + + [ Ricardo Mendoza ] + * compat/media: improve client death notification registration and handler + + -- Ricardo Salveti de Araujo Wed, 05 Nov 2014 18:15:23 -0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu30) vivid; urgency=medium + + [ Jim Hodapp ] + * Add direct_camera_test support for setting the thumbnail size. + + -- Ricardo Salveti de Araujo Tue, 04 Nov 2014 20:37:09 -0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu29) vivid; urgency=medium + + [ Jim Hodapp ] + * Add hybris API that allows retrieval of supported camera still + image thumbnail sizes that qtubuntu-camera can take advantage of. + + -- Ricardo Salveti de Araujo Thu, 30 Oct 2014 22:38:05 -0400 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu28) utopic; urgency=medium + + [ Alfonso Sanchez-Beato ] + * media/compat: Add CSD to data for configuring codec (LP: #1378397) + + [ Ricardo Mendoza ] + * Implement Observer interface for the MediaRecorder class + (LP: #1362658) + + -- Ricardo Salveti de Araujo Tue, 14 Oct 2014 22:05:15 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu27) utopic; urgency=medium + + * debian/rules: using hardening=-stackprotectorstrong as that's not + supported with gcc 4.7 + + -- Ricardo Salveti de Araujo Fri, 19 Sep 2014 03:34:34 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu26) utopic; urgency=medium + + [ Yu-Cheng Chou ] + * debian/control: fix typo in description (LP: #1259444) + + [ Daniel van Vugt ] + * hooks: converting linear search into a binary search + (LP: #1343198) + + -- Ricardo Salveti de Araujo Thu, 14 Aug 2014 17:45:44 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu25) utopic; urgency=medium + + [ Alfonso Sanchez-Beato ] + * Adding support for the wifi HAL + + -- Ricardo Salveti de Araujo Wed, 13 Aug 2014 01:32:42 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu24) utopic; urgency=medium + + [ Jim Hodapp ] + * Moved audio record source files from libhybris source tree to + frameworks/av/media/libmedia + + -- Ricardo Salveti de Araujo Wed, 06 Aug 2014 17:10:52 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu23) utopic; urgency=medium + + [ Jim Hodapp ] + * compat/camera: export additional interface and logic for audio + support when recording videos + + -- Ricardo Salveti de Araujo Tue, 05 Aug 2014 17:02:19 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu22) utopic; urgency=medium + + * compat: roll back local changes for native buffer allocators + + -- Ricardo Salveti de Araujo Thu, 24 Jul 2014 02:29:36 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu21) utopic; urgency=medium + + * compat/camera: adding metadata setter for GPS location + + -- Ricardo Salveti de Araujo Wed, 16 Jul 2014 16:08:09 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu20) utopic; urgency=medium + + * Added function to retrieve list of supported camera's scene modes + + -- Ricardo Salveti de Araujo Fri, 11 Jul 2014 12:10:49 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu19) utopic; urgency=medium + + * Added Camera's scene mode parameter value for HDR + * compat/camera: adding extras required by the mtk bsp + + -- Ricardo Salveti de Araujo Tue, 08 Jul 2014 19:51:08 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu18) utopic; urgency=medium + + [ Jim Hodapp ] + * compat: adding camera_service, also exporting the media_recorder + functionality + + [ Ricardo Salveti de Araujo ] + * Makefile.am: installing additional header for media_recorder + * debian/control: bumping standards-version to 3.9.5 + + -- Ricardo Salveti de Araujo Tue, 24 Jun 2014 11:42:07 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu17) utopic; urgency=medium + + * Enabling test_lights again (with fixes) + * test_audio.c: retry stream_out in case it fails in the first try + + -- Ricardo Salveti de Araujo Tue, 17 Jun 2014 22:47:51 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu16) utopic; urgency=medium + + * test_audio.c: improving test, creating both input and output streams + + -- Ricardo Salveti de Araujo Thu, 22 May 2014 20:26:57 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu15) utopic; urgency=medium + + * tests/Makefile.am: adding test_audio back + + -- Ricardo Salveti de Araujo Mon, 19 May 2014 16:52:16 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu14) trusty; urgency=medium + + * Make sure a client can render video if it connects to media-hub a + second time. + + -- Ricardo Salveti de Araujo Fri, 04 Apr 2014 11:16:27 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu13) trusty; urgency=medium + + * Add media-hub support (out of process video decoding). + + -- Ricardo Salveti de Araujo Thu, 27 Mar 2014 11:50:09 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu12) trusty; urgency=medium + + * input: add method to check if compat side is available + + -- Ricardo Salveti de Araujo Wed, 19 Mar 2014 22:23:43 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu11) trusty; urgency=medium + + * hardware.c: hw_get_module should return an error if module not found, + instead of crashing with SIGSEGV (LP: #1208862) + + -- Ricardo Salveti de Araujo Wed, 19 Mar 2014 19:07:57 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu10) trusty; urgency=medium + + [ Iain Lane ] + * Turn on wayland support to provide libwayland-egl, which mesa in Ubuntu + relies on. This makes libhybris a viable provider of the + _egl_conf alternate. (LP: #1206371) + + [ Ricardo Salveti de Araujo ] + * debian/rules: changing default alternatives priority to be lower than + the one provided by mesa (EGL/GLES), avoid breaking normal desktop + (LP: #1232962) + + -- Ricardo Salveti de Araujo Tue, 18 Mar 2014 21:47:34 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu9) trusty; urgency=medium + + * camera_compatibility_layer.cpp: in our case the texture is controlled by + the app (avoid locks in gl consumer) LP: #1282701 + + -- Ricardo Salveti de Araujo Mon, 03 Mar 2014 14:24:20 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu8) trusty; urgency=medium + + * common: also protecting the bionic system property calls + + -- Ricardo Salveti de Araujo Wed, 26 Feb 2014 01:34:19 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu7) trusty; urgency=medium + + * media: fixing code for 4.4 and improving the release_output_buffer logic + + -- Ricardo Salveti de Araujo Fri, 21 Feb 2014 00:57:19 -0300 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu6) trusty; urgency=medium + + * Making compat code compatible with Android 4.4.2 + + -- Ricardo Salveti de Araujo Thu, 23 Jan 2014 02:38:35 -0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu5) trusty; urgency=medium + + * Allowing grouper to share the shm block between users for usc + + -- Ricardo Salveti de Araujo Tue, 14 Jan 2014 20:01:25 -0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu4) trusty; urgency=low + + * debian/control: fix typo in descriptions (LP: #1255726, LP: #1259341) + + -- Benjamin Kerensa Sun, 05 Jan 2014 13:37:00 -0800 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu3) trusty; urgency=low + + * compat/media, hybris/media: removing singleton and simplifying the code now + that most of the sync logic is happening in gstreamer + + -- Ricardo Salveti de Araujo Mon, 23 Dec 2013 15:04:51 -0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu2) trusty; urgency=low + + * hybris/media: adding missing surface_texture_client_hardware_rendering + function in surface_texture_client_hybris.h, that got removed during a + rebase conflict. + + -- Ricardo Salveti de Araujo Thu, 19 Dec 2013 13:20:26 -0200 + +libhybris (0.1.0+git20131207+e452e83-0ubuntu1) trusty; urgency=low + + * New upstream snapshot: + - Rebasing patches and removing the ones that are already available in + upstream + - Performance improvements for the glesv2 hybris driver + - android-platform-headers renamed and migrated to a different source + package (android-headers) + - Most libraries can now be used via a pkg-config file + + -- Ricardo Salveti de Araujo Wed, 11 Dec 2013 01:31:48 -0200 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu37) trusty; urgency=low + + * Mark android-platform-headers Multi-Arch: foreign, so that libhardware-dev + is cross-installable. + * Use the right compiler if set up for cross-compiling. + Cross-build-dependencies won't work right due to the dep on + gcc-4.7/g++-4.7, but this will work better than anything else and you can + satisfy the build-deps by hand for now. + + -- Steve Langasek Sat, 23 Nov 2013 05:41:05 +0000 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu36) trusty; urgency=low + + * 0035-hooks.c-adding-hooks-for-asprintf-and-vasprintf-both.patch: + - Missing hooks needed by the emulator EGL/GLES driver + + -- Ricardo Salveti de Araujo Thu, 14 Nov 2013 17:34:51 -0200 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu35) saucy; urgency=low + + * 0034-Support-for-software-rendering-and-buffer-management.patch: + - Add a getter function that allows a client app to check to see if we + are doing hardware rendering. + + -- Ricardo Salveti de Araujo Mon, 14 Oct 2013 17:04:02 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu34) saucy; urgency=low + + * 0034-Support-for-software-rendering-and-buffer-management.patch: + - Enable support for software rendering and improving buffer management + when decoding/rendering a video + + -- Ricardo Salveti de Araujo Wed, 09 Oct 2013 18:46:48 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu33) saucy; urgency=low + + * 0033-hardware-adding-missing-power.h.patch: + - Adding missing libhardware power.h header + + -- Ricardo Salveti de Araujo Wed, 09 Oct 2013 11:48:44 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu32) saucy; urgency=low + + * 0032-Make-the-decoding-rendering-loop-much-more-robust.-F.patch: + - Making the decoding/rendering loop more robust by releasing + the output buffers in case the hal call fails (LP: #1234207) + + -- Ricardo Salveti de Araujo Wed, 02 Oct 2013 22:48:24 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu31) saucy; urgency=low + + * 0031-Fixes-bug-lp-1234007-out-of-index-crash-for-handling.patch: + - Fixing an out of index crash when handling media_codec_layer output + buffers list (LP: #1234007) + + -- Ricardo Salveti de Araujo Wed, 02 Oct 2013 11:35:46 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu30) saucy; urgency=low + + * 0030-compat-media-also-support-decoding-with-playbin.patch: + - Refreshing patch adding another method to ask when the client is ready + for rendering + + -- Ricardo Salveti de Araujo Mon, 30 Sep 2013 16:08:45 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu29) saucy; urgency=low + + * 0030-compat-media-also-support-decoding-with-playbin.patch: + - Improving rendering/decoding handling to also work with playbin + + -- Ricardo Salveti de Araujo Fri, 27 Sep 2013 13:54:55 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu28) saucy; urgency=low + + * 0029-compat-input-take-full-geometry-by-default-in-input-.patch: + - Removing surfaceflinger dependency of the input stack by allowing the + consumer to pass the screen width and height + + -- Ricardo Salveti de Araujo Wed, 25 Sep 2013 23:21:51 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu27) saucy; urgency=low + + * 0028-surface_texture_client_hybris-using-float-instead-of.patch: + - Using float directly instead of GLfloat to avoid conflicts with Qt + + -- Ricardo Salveti de Araujo Fri, 13 Sep 2013 10:30:57 -0400 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu26) saucy; urgency=low + + * 0027-media-provide-a-method-to-check-the-compat-availabil.patch: + - Provide a runtime method to check if the media compat layer is available + in the system (/system from Android) + + -- Ricardo Salveti de Araujo Thu, 12 Sep 2013 11:13:39 -0400 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu25) saucy; urgency=low + + * 0026-Added-a-function-to-get-the-transformation-matrix-an.patch: + - Adding extra surface texture calls for media playback + + -- Ricardo Salveti de Araujo Wed, 11 Sep 2013 10:33:17 -0400 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu24) saucy; urgency=low + + * Moving the media HAL into a separated package (libmedia), so we can have + the proper package dependencies in the gst-plugins-bad package (otherwise + it ends up depending on libhybris, which breaks EGL for desktop). + + -- Ricardo Salveti de Araujo Tue, 10 Sep 2013 10:40:32 -0400 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu23) saucy; urgency=low + + * 0025-audio.h-handling-the-float-based-function-calls-with.patch: + - Using proper aapcs attribute to the float based function calls in the + audio HAL + + -- Ricardo Salveti de Araujo Tue, 10 Sep 2013 09:48:48 -0400 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu22) saucy; urgency=low + + * 0024-compat-input-block-poll-avoid-waking-up-at-every-500.patch: + - Block poll when retrieving the input events via HAL, to avoid waking up + at every 500 ms + + -- Ricardo Salveti de Araujo Wed, 04 Sep 2013 21:21:34 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu21) saucy; urgency=low + + * 0010-hardware-include-adding-audio-hal-related-headers-fr.patch: + - Updating patch to really reflect headers from android-4.2.2_r1.2 + + -- Ricardo Salveti de Araujo Thu, 29 Aug 2013 00:05:31 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu20) saucy; urgency=low + + * 0023-compat-media-make-use-of-NativeBufferAllocator-inste.patch: + - Make media use a native buffer allocator so we don't need to depend on + surface flinger + + -- Ricardo Salveti de Araujo Wed, 28 Aug 2013 17:37:10 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu19) saucy; urgency=low + + * 0022-compat-camera-make-use-of-native-buffer-allocator-in.patch: + - Make camera use a native buffer allocator so we don't need to depend on + surface flinger + + -- Ricardo Salveti de Araujo Tue, 27 Aug 2013 17:08:03 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu18) saucy; urgency=low + + * 0021-hooks.c-also-add-a-matching-sysconf-for-_SC_NPROCESS.patch: + - Add a matching sysconf for _SC_NPROCESSORS_ONLN, used by libstagefright + + -- Ricardo Salveti de Araujo Mon, 26 Aug 2013 18:22:29 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu17) saucy; urgency=low + + * 0020-Change-the-SurfaceTextureClientUbuntu-API-to-be-sing.patch: + - Change API to be singleton-based to work around Gstreamer playbin + weirdness. + + -- Ricardo Salveti de Araujo Mon, 26 Aug 2013 11:10:11 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu16) saucy; urgency=low + + * 0019-Fix-last-argument-to-pthread_cond_timedwait.patch: + - Fixing last argument of pthread_cond_timedwait so it can work as + expected. + + -- Ricardo Salveti de Araujo Fri, 09 Aug 2013 10:51:32 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu15) saucy; urgency=low + + * 0018-properties.c-better-handling-for-name-and-value-size.patch: + - Better handling key and size names, avoid overflow issue with a blob + used by nexus 4 (libqmi_cci.so) - bug found by diwic + + -- Ricardo Salveti de Araujo Fri, 09 Aug 2013 07:51:28 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu14) saucy; urgency=low + + * debian/control: doing proper replaces/breaks for the new packages + + -- Ricardo Salveti de Araujo Tue, 06 Aug 2013 19:12:43 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu13) saucy; urgency=low + + * debian/control: + - Creating android-platform-headers that contains the original Android + headers. This will later come from a different src package once we + rebase libhybris with current upstream. + - Moving libhardware2 and libhybris-common into separated packages, + so we don't have libmirclient depending on the egl/gles libraries. + - Split for other packages should happen once the library is renamed + with upstream, so we can use libhybris/android-foo instead + * 0017-common-hooks.c-handle-null-attr-in-pthread_rwlock_in.patch: + - Handle null attr in pthread_rwlock_init, as it's a valid use case + + -- Ricardo Salveti de Araujo Tue, 06 Aug 2013 15:44:07 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu12) saucy; urgency=low + + * 0016-media-adding-files-for-media-codec-support-with-stag.patch: + - Adding media codec support to allow video decode using libstagefright + directly + + -- Ricardo Salveti de Araujo Wed, 31 Jul 2013 23:31:32 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu11) saucy; urgency=low + + * 0015-camera_compatibility_layer.cpp-don-t-explicitly-rele.patch: + - Don't explicitly release frames, avoid crash on manta + + -- Ricardo Salveti de Araujo Thu, 18 Jul 2013 04:14:07 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu10) saucy; urgency=low + + * debian/control: including missing ui headers into libhybris-dev + (LP: #1199953) + * 0014-input_compatibility_layer.cpp-avoid-blocking-on-exit.patch: avoid + blocking on exit and shutdown (LP: #1199897) + + -- Ricardo Salveti de Araujo Wed, 10 Jul 2013 19:36:09 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu9) saucy; urgency=low + + * debian/control: build only for armhf, i386 and amd64 + + -- Ricardo Salveti de Araujo Mon, 01 Jul 2013 19:27:07 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu8) saucy; urgency=low + + * 0013-implement-getset-property-via-property-service.patch: + - Adding support for get/set property using the Android property service + * libandroid-properties1: new library to export the property_get, + property_set and property_list android calls + * libhybris-utils: new package providing the getprop and setprop utilities + + -- Ricardo Salveti de Araujo Mon, 01 Jul 2013 18:50:12 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu7) saucy; urgency=low + + * Forcing GCC 4.7, to avoid issues with 4.8 ABI changes (temporarily until + the android side can be built with 4.8 as well) + + -- Ricardo Salveti de Araujo Wed, 26 Jun 2013 18:19:13 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu6) saucy; urgency=low + + * Adding 0012-hooks.c-handle-invalid-mutex-in-pthread_mutex_destro.patch: + - Handling invalid mutex in pthread_mutex_destroy + + -- Ricardo Salveti de Araujo Tue, 25 Jun 2013 00:45:56 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu5) saucy; urgency=low + + * 0010-hardware-include-adding-audio-hal-related-headers-fr.patch: + - Updating based on the version set upstream + * Adding 0011-hooks.c-no-need-to-map-strcasestr.patch: + - Remove hook for strcasesrt, glibc verision behaves differently + + -- Ricardo Salveti de Araujo Mon, 24 Jun 2013 23:03:45 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu4) saucy; urgency=low + + * Adding 0010-hardware-include-adding-audio-hal-related-headers-fr.patch: + - Exporting headers needed to access the Android Audio HAL + + -- Ricardo Salveti de Araujo Mon, 24 Jun 2013 01:28:22 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu3) saucy; urgency=low + + * Adding 0009-jb-linker.c-reduce-debugging-output-for-prelinked-li.patch: + - Reducing debugging output for the prelinked library detection logic + + -- Ricardo Salveti de Araujo Wed, 19 Jun 2013 22:28:28 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu2) saucy; urgency=low + + * Adding 0008-hooks-shm-fixing-logic-with-cond-is-negative-error.patch: + - Fixing int -> unsigned int conversion when handling android shared cond + + -- Ricardo Salveti de Araujo Fri, 14 Jun 2013 05:57:51 -0300 + +libhybris (0.1.0+git20130606+c5d897a-0ubuntu1) saucy; urgency=low + + * New upstream snapshot + * Updating patches against latest upstream, dropping (already merged): + - 0005-egl-platform-common-implement-conversion-to-base-buf.patch + - 0006-hooks-using-shm-hybris-pshared.patch + * Fixing logging support, adding: + - 0006-jb-linker.c-allow-debug-of-the-linker-and-hooked-sym.patch + - 0007-jb-linker.c-ubuntu-touch-uses-dev-alog-instead-of-de.patch + + -- Ricardo Salveti de Araujo Fri, 07 Jun 2013 02:54:18 -0300 + +libhybris (0.1.0+git20130606+6f67260-0ubuntu1) saucy; urgency=low + + * New upstream snapshot + * Updating patches against latest upstream + * debian/rules: moving get-orig-source to get-packaged-orig-source + * debian/patches/0005-egl-platform-common-implement-conversion-to-base-buf.patch: + Implement native conversion to base buffer class + * debian/patches/0006-hooks-using-shm-hybris-pshared.patch: use SHM between + hybris instances for pshared mutex and condition (needed by MIR) + + -- Ricardo Salveti de Araujo Wed, 05 Jun 2013 22:22:02 -0300 + +libhybris (0.1.0+git20130604+1b671a8-0ubuntu1) saucy; urgency=low + + * New upstream snapshot + * Removed patches that are now available in upstream: + - 0001-hybris-include-separating-include-files-per-director.patch + - 0002-Input-adding-initial-compat-files-for-input.patch + - 0005-common-hooks.c-adding-hooks-used-by-the-ubuntu-media.patch + - 0007-common-properties.c-also-probe-property-from-kernel-.patch + - 0008-common-linkers-removing-Android.mk-files-are-they-ar.patch + + -- Ricardo Salveti de Araujo Tue, 04 Jun 2013 14:25:42 -0300 + +libhybris (0.1.0+git20130601+dfb2e26-0ubuntu2) saucy; urgency=low + + * debian/copyright: fixing license and copyright entries based on a review + done by Sebastien Bacher + + -- Ricardo Salveti de Araujo Tue, 04 Jun 2013 07:33:11 -0300 + +libhybris (0.1.0+git20130601+dfb2e26-0ubuntu1) saucy; urgency=low + + * Initial release for Ubuntu + + -- Ricardo Salveti de Araujo Tue, 04 Jun 2013 02:58:01 -0300 diff --git a/debian/compat b/debian/compat new file mode 100644 index 000000000..ec635144f --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 000000000..eed17a811 --- /dev/null +++ b/debian/control @@ -0,0 +1,178 @@ +# This file is autogenerated. DO NOT EDIT! +# +# Modifications should be made to debian/control.in instead. +# This file is regenerated automatically in the clean target. +Source: libhybris +Priority: extra +Maintainer: Ubuntu Developers +Build-Depends: debhelper (>= 9.0.0), + autotools-dev, + dh-autoreconf, + android-headers (>= 4.4.2), + quilt, + pkg-config, + libgles2-mesa-dev, + libwayland-dev +Standards-Version: 3.9.7 +Section: libs +Vcs-Git: https://git.launchpad.net/~libhybris-maintainers/libhybris/+git/libhybris +Vcs-Browser: https://git.launchpad.net/~libhybris-maintainers/libhybris/+git/libhybris/ + +Package: libandroid-properties1 +Architecture: armhf arm64 i386 amd64 +Depends: ${shlibs:Depends}, + ${misc:Depends} +Description: Library to provide access to get, set and list Android properties + Contains a library that provides access to get, set and list Android + properties, which can be used by any Ubuntu app that needs to probe + for properties (gps, modem, device specifics). + +Package: libandroid-properties-dev +Section: libdevel +Architecture: armhf arm64 i386 amd64 +Depends: libandroid-properties1 (= ${binary:Version}), + ${misc:Depends} +Description: Development headers files for libandroid-properties + Contains the development files for use in applications that wants to get, + set or list the Android properties. + +Package: libmedia1 +Architecture: armhf arm64 i386 amd64 +Depends: ${shlibs:Depends}, + ${misc:Depends} +Replaces: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu24) +Breaks: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu24) +Description: Library to provide access to the Android Media HAL + Contains a library that provides access to the Android Media HAL, + which abstract the access to the Android libstagefright based + decoders. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libmedia-dev +Section: libdevel +Architecture: armhf arm64 i386 amd64 +Depends: libmedia1 (= ${binary:Version}), + android-headers (>= 4.4.2), + ${misc:Depends} +Replaces: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu24) +Breaks: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu24) +Description: Development files for libmedia + Contains the development files for the Android Media HAL, which + abstract the access to the Android libstagefright based decoders. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhardware2 +Architecture: armhf arm64 i386 amd64 +Depends: ${shlibs:Depends}, + ${misc:Depends} +Replaces: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Breaks: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Description: Library to provide access to the Android libhardware HAL + Contains a library that provides access to the Android libhardware HAL, + which can be used to access a wide range of other HALs, such as audio, + power, gralloc, etc. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhardware-dev +Section: libdevel +Architecture: armhf arm64 i386 amd64 +Depends: libhardware2 (= ${binary:Version}), + android-headers (>= 4.4.2), + ${misc:Depends} +Replaces: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Breaks: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Description: Development files for libhardware + Contains the development files for the Android libhardware HAL, which can + be used to access a wide range of other HALs, such as audio, power, + gralloc, etc. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris-common1 +Architecture: armhf arm64 i386 amd64 +Depends: ${shlibs:Depends}, + ${misc:Depends} +Replaces: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Breaks: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Description: Common library that contains the Android linker and custom hooks + Contains a common library that contains the Android linker, used to + dynamically load and use symbols from Android based libraries. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris-common-dev +Section: libdevel +Architecture: armhf arm64 i386 amd64 +Depends: libhybris-common1 (= ${binary:Version}), + ${misc:Depends} +Replaces: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Breaks: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Description: Development files for libhybris-common + Contains the development files for the common library that contains the + Android linker, used to dynamically load and use symbols from Android + based libraries. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris +Architecture: armhf arm64 i386 amd64 +Depends: libandroid-properties1 (= ${binary:Version}), + libhardware2, + libmedia1, + ${shlibs:Depends}, + ${misc:Depends} +Description: Allows to run bionic-based HW adaptations in glibc systems - libs + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris-dev +Section: libdevel +Architecture: armhf arm64 i386 amd64 +Depends: libhybris (= ${binary:Version}), + android-headers (>= 4.4.2), + libandroid-properties-dev (= ${binary:Version}), + libhardware-dev (= ${binary:Version}), + libmedia-dev (= ${binary:Version}), + libhybris-common-dev (= ${binary:Version}), + ${misc:Depends}, + libgles2-mesa-dev, +Description: Development headers and libraries for libhybris + Contains the header files for use in developing applications that use + the libhybris library. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris-utils +Section: utils +Architecture: armhf arm64 i386 amd64 +Depends: libhybris (= ${binary:Version}), + ${shlibs:Depends}, + ${misc:Depends} +Description: Utilities to help working with the Android HW abstraction layer + Contains utilities used to help working with Android HW abstraction layer. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris-test +Section: devel +Architecture: armhf arm64 i386 amd64 +Depends: libhybris (= ${binary:Version}), + ${shlibs:Depends}, + ${misc:Depends} +Description: Allows to run bionic-based HW adaptations in glibc systems - tests + Contains the test applications used to validate libhybris (needs Android + libraries or container). + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. diff --git a/debian/control.in b/debian/control.in new file mode 100644 index 000000000..b8253b678 --- /dev/null +++ b/debian/control.in @@ -0,0 +1,175 @@ +Source: libhybris +Priority: extra +Maintainer: Ubuntu Developers +Build-Depends: debhelper (>= 9.0.0), + autotools-dev, + dh-autoreconf, + android-headers (>= 4.4.2), + @EXTRA_BUILD_DEPENDS@ + quilt, + pkg-config, + libgles2-mesa-dev, + libwayland-dev +Standards-Version: 3.9.7 +Section: libs +Vcs-Git: https://git.launchpad.net/~libhybris-maintainers/libhybris/+git/libhybris +Vcs-Browser: https://git.launchpad.net/~libhybris-maintainers/libhybris/+git/libhybris/ + +Package: libandroid-properties1 +Architecture: armhf arm64 i386 amd64 +Depends: ${shlibs:Depends}, + ${misc:Depends} +Description: Library to provide access to get, set and list Android properties + Contains a library that provides access to get, set and list Android + properties, which can be used by any Ubuntu app that needs to probe + for properties (gps, modem, device specifics). + +Package: libandroid-properties-dev +Section: libdevel +Architecture: armhf arm64 i386 amd64 +Depends: libandroid-properties1 (= ${binary:Version}), + ${misc:Depends} +Description: Development headers files for libandroid-properties + Contains the development files for use in applications that wants to get, + set or list the Android properties. + +Package: libmedia1 +Architecture: armhf arm64 i386 amd64 +Depends: ${shlibs:Depends}, + ${misc:Depends} +Replaces: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu24) +Breaks: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu24) +Description: Library to provide access to the Android Media HAL + Contains a library that provides access to the Android Media HAL, + which abstract the access to the Android libstagefright based + decoders. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libmedia-dev +Section: libdevel +Architecture: armhf arm64 i386 amd64 +Depends: libmedia1 (= ${binary:Version}), + android-headers (>= 4.4.2), + ${misc:Depends} +Replaces: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu24) +Breaks: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu24) +Description: Development files for libmedia + Contains the development files for the Android Media HAL, which + abstract the access to the Android libstagefright based decoders. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhardware2 +Architecture: armhf arm64 i386 amd64 +Depends: ${shlibs:Depends}, + ${misc:Depends} +Replaces: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Breaks: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Description: Library to provide access to the Android libhardware HAL + Contains a library that provides access to the Android libhardware HAL, + which can be used to access a wide range of other HALs, such as audio, + power, gralloc, etc. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhardware-dev +Section: libdevel +Architecture: armhf arm64 i386 amd64 +Depends: libhardware2 (= ${binary:Version}), + android-headers (>= 4.4.2), + ${misc:Depends} +Replaces: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Breaks: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Description: Development files for libhardware + Contains the development files for the Android libhardware HAL, which can + be used to access a wide range of other HALs, such as audio, power, + gralloc, etc. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris-common1 +Architecture: armhf arm64 i386 amd64 +Depends: ${shlibs:Depends}, + ${misc:Depends} +Replaces: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Breaks: libhybris (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Description: Common library that contains the Android linker and custom hooks + Contains a common library that contains the Android linker, used to + dynamically load and use symbols from Android based libraries. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris-common-dev +Section: libdevel +Architecture: armhf arm64 i386 amd64 +Depends: libhybris-common1 (= ${binary:Version}), + ${misc:Depends} +Replaces: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Breaks: libhybris-dev (<< 0.1.0+git20130606+c5d897a-0ubuntu13) +Description: Development files for libhybris-common + Contains the development files for the common library that contains the + Android linker, used to dynamically load and use symbols from Android + based libraries. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris +Architecture: armhf arm64 i386 amd64 +Depends: libandroid-properties1 (= ${binary:Version}), + libhardware2, + libmedia1, + ${shlibs:Depends}, + ${misc:Depends} +Description: Allows to run bionic-based HW adaptations in glibc systems - libs + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris-dev +Section: libdevel +Architecture: armhf arm64 i386 amd64 +Depends: libhybris (= ${binary:Version}), + android-headers (>= 4.4.2), + libandroid-properties-dev (= ${binary:Version}), + libhardware-dev (= ${binary:Version}), + libmedia-dev (= ${binary:Version}), + libhybris-common-dev (= ${binary:Version}), + ${misc:Depends}, + libgles2-mesa-dev, +Description: Development headers and libraries for libhybris + Contains the header files for use in developing applications that use + the libhybris library. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris-utils +Section: utils +Architecture: armhf arm64 i386 amd64 +Depends: libhybris (= ${binary:Version}), + ${shlibs:Depends}, + ${misc:Depends} +Description: Utilities to help working with the Android HW abstraction layer + Contains utilities used to help working with Android HW abstraction layer. + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. + +Package: libhybris-test +Section: devel +Architecture: armhf arm64 i386 amd64 +Depends: libhybris (= ${binary:Version}), + ${shlibs:Depends}, + ${misc:Depends} +Description: Allows to run bionic-based HW adaptations in glibc systems - tests + Contains the test applications used to validate libhybris (needs Android + libraries or container). + . + Hybris is a solution that allows the use of bionic-based HW adaptations in + glibc systems. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 000000000..299c94801 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,539 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: libhybris +Source: https://github.com/libhybris/libhybris + +Files: * +Copyright: 2012-2014, 2016, Canonical Ltd +License: Apache-2.0 + +Files: compat/media/SimplePlayer.cpp + compat/media/SimplePlayer.h + compat/media/codec.cpp +Copyright: 2005-2008, 2010, 2012-2015, The Android Open Source Project +License: Apache-2.0 + +Files: compat/media/media_recorder.cpp + compat/media/media_recorder.h +Copyright: 2013, 2014, Canonical Ltd + 2008, The Android Open Source Project +License: Apache-2.0 + +Files: compat/ui/* +Copyright: 2012, 2013, Simon Busch +License: Apache-2.0 + +Files: hybris/common/* +Copyright: 2008-2015, The Android Open Source Project +License: BSD-2-clause + +Files: hybris/common/dlfcn.c +Copyright: 2013, Intel Corporation +License: Apache-2.0 + +Files: hybris/common/gingerbread/NOTICE + hybris/common/gingerbread/dlfcn.c +Copyright: 2005-2008, 2010, 2012-2015, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/common/hooks.c +Copyright: 2013, Christophe Chapuis + 2012, Carsten Munk + 2012, Canonical Ltd +License: Apache-2.0 + +Files: hybris/common/hooks_shm.c +Copyright: 2013, Christophe Chapuis + 2012, Carsten Munk +License: Apache-2.0 + +Files: hybris/common/hooks_shm.h +Copyright: 2012, Carsten Munk +License: Apache-2.0 + +Files: hybris/common/ics/dlfcn.c +Copyright: 2005-2008, 2010, 2012-2015, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/common/jb/dlfcn.c +Copyright: 2005-2008, 2010, 2012-2015, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/common/logging.c + hybris/common/logging.h +Copyright: 2013, Thomas Perl +License: Apache-2.0 + +Files: hybris/common/mm/* +Copyright: 2005-2008, 2010, 2012-2015, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/common/mm/bionic/* +Copyright: 2008-2015, The Android Open Source Project +License: BSD-2-clause + +Files: hybris/common/mm/bionic/libc/include/android/dlext.h +Copyright: 2005-2008, 2010, 2012-2015, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/common/mm/bionic/libc/private/* +Copyright: 2005-2008, 2010, 2012-2015, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/common/mm/bionic/libc/private/ThreadLocalBuffer.h + hybris/common/mm/bionic/libc/private/__get_tls.h + hybris/common/mm/bionic/libc/private/bionic_asm.h + hybris/common/mm/bionic/libc/private/bionic_auxv.h + hybris/common/mm/bionic/libc/private/bionic_futex.h + hybris/common/mm/bionic/libc/private/bionic_lock.h + hybris/common/mm/bionic/libc/private/bionic_mbstate.h + hybris/common/mm/bionic/libc/private/bionic_ssp.h + hybris/common/mm/bionic/libc/private/bionic_time.h + hybris/common/mm/bionic/libc/private/bionic_time_conversions.h + hybris/common/mm/bionic/libc/private/bionic_tls.h + hybris/common/mm/bionic/libc/private/libc_events.h + hybris/common/mm/bionic/libc/private/libc_logging.h +Copyright: 2008-2015, The Android Open Source Project +License: BSD-2-clause + +Files: hybris/common/mm/hybris_compat.cpp + hybris/common/mm/hybris_compat.h + hybris/common/mm/linker.cpp + hybris/common/mm/linker.h + hybris/common/mm/linker_debug.h + hybris/common/mm/linker_phdr.cpp + hybris/common/mm/linker_phdr.h + hybris/common/mm/rt.cpp +Copyright: 2008-2015, The Android Open Source Project +License: BSD-2-clause + +Files: hybris/common/strlcat.c +Copyright: 1998, Todd C. Miller +License: ISC + +Files: hybris/common/strlcpy.c +Copyright: 1998, Todd C. Miller +License: ISC + +Files: hybris/common/stub/* +Copyright: 2012-2014, 2016, Canonical Ltd +License: Apache-2.0 + +Files: hybris/common/sysconf.c +Copyright: 2013, Adrian Negreanu +License: Apache-2.0 + +Files: hybris/egl/* +Copyright: 2012-2014, Jolla Ltd +License: Apache-2.0 + +Files: hybris/egl/egl.c +Copyright: 2012, Carsten Munk +License: Apache-2.0 + +Files: hybris/egl/eglhybris.h +Copyright: 2012, 2013, Simon Busch +License: Apache-2.0 + +Files: hybris/egl/platforms/* +Copyright: 2013, libhybris +License: Apache-2.0 + +Files: hybris/egl/platforms/common/* +Copyright: 2012, Collabora, Ltd +License: MIT2 + Permission to use, copy, modify, distribute, and sell this software and + its documentation for any purpose is hereby granted without fee, provided + that the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation, and that the name of the copyright holders not be used in + advertising or publicity pertaining to distribution of the software + without specific, written prior permission. The copyright holders make + no representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied warranty. + . + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, 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. + +Files: hybris/egl/platforms/common/hybris_nativebufferext.h +Copyright: 2013, Jolla Ltd + 2011, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/egl/platforms/common/native_handle.c +Copyright: 2005-2008, 2010, 2012-2015, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/egl/platforms/common/server_wlegl_handle.h + hybris/egl/platforms/common/windowbuffer.cpp + hybris/egl/platforms/common/windowbuffer.h +Copyright: 2012, Collabora, Ltd +License: BSD-2-clause + +Files: hybris/egl/platforms/wayland/* +Copyright: 2013, Jolla Ltd +License: LGPL-2.1 + +Files: hybris/egl/ws.c +Copyright: 2013, libhybris +License: Apache-2.0 + +Files: hybris/glesv1/* +Copyright: 2012-2014, Jolla Ltd +License: Apache-2.0 + +Files: hybris/glesv2/* +Copyright: 2012, Carsten Munk +License: Apache-2.0 + +Files: hybris/hardware/* +Copyright: 2012, 2013, Simon Busch +License: Apache-2.0 + +Files: hybris/include/* +Copyright: 2007-2012, The Khronos Group Inc +License: Expat + +Files: hybris/include/EGL/eglmesaext.h +Copyright: 2008, Tungsten Graphics, Inc., Cedar Park, Texas +License: Expat + +Files: hybris/include/GL/gl.h +Copyright: 2009, VMware, Inc. + 1999-2006, Brian Paul +License: Expat + +Files: hybris/include/GL/glx.h + hybris/include/GL/glx_mangle.h + hybris/include/GL/osmesa.h +Copyright: 1999-2006, Brian Paul +License: Expat + +Files: hybris/include/GL/internal/* +Copyright: IBM Corporation 2004, / 2007-2008, Red Hat, Inc / 1998-1999, Precision Insight, Inc., Cedar Park, Texas +License: Expat + +Files: hybris/include/GL/internal/sarea.h +Copyright: 2000, VA Linux Systems, Inc + 1998, 1999, Precision Insight, Inc., Cedar Park, Texas +License: Expat + +Files: hybris/include/GL/wmesa.h +Copyright: 1995-1998, Brian Paul +License: LGPL-2+ + +Files: hybris/include/GLES/* +Copyright: 2010-2012 Silicon Graphics, Inc +License: SGI-2.0 + +Files: hybris/include/GLES2/* +Copyright: 2010-2012 Silicon Graphics, Inc +License: SGI-2.0 + +Files: hybris/include/VG/* +Copyright: 2008, The Khronos Group Inc +License: X11/MIT + +Files: hybris/include/hybris/* +Copyright: 2012-2014, 2016, Canonical Ltd +License: Apache-2.0 + +Files: hybris/include/hybris/common/binding.h +Copyright: 2013, Simon Busch + 2013, Jolla Ltd. + 2012, Canonical Ltd +License: Apache-2.0 + +Files: hybris/include/hybris/common/dlfcn.h +Copyright: 2013, Intel Corporation +License: Apache-2.0 + +Files: hybris/include/hybris/common/floating_point_abi.h +Copyright: 2012-2014, Jolla Ltd +License: Apache-2.0 + +Files: hybris/include/hybris/dlfcn/* +Copyright: 2013, Intel Corporation +License: Apache-2.0 + +Files: hybris/include/hybris/properties/* +Copyright: 2013, Simon Busch + 2013, Canonical Ltd + 2012, Carsten Munk + 2008, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/include/hybris/ui/* +Copyright: 2012, 2013, Simon Busch +License: Apache-2.0 + +Files: hybris/libnfc_ndef_nxp/* +Copyright: 2012-2014, Jolla Ltd +License: Apache-2.0 + +Files: hybris/libnfc_nxp/* +Copyright: 2012-2014, Jolla Ltd +License: Apache-2.0 + +Files: hybris/libsync/* +Copyright: 2012, Google, Inc +License: Apache-2.0 + +Files: hybris/properties/* +Copyright: 2013, Simon Busch + 2013, Canonical Ltd + 2012, Carsten Munk + 2008, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/properties/cache.c +Copyright: 2013, Simon Busch + 2013, Jolla Ltd. + 2013, Canonical Ltd + 2012, Carsten Munk + 2008, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/properties/properties_p.h +Copyright: 2013, Jolla Ltd. +License: Apache-2.0 + +Files: hybris/properties/runtime_cache.c +Copyright: 2015, Jolla Ltd. + 2013, Simon Busch + 2013, Jolla Ltd. + 2013, Canonical Ltd + 2012, Carsten Munk + 2008, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/tests/test_egl.c + hybris/tests/test_glesv2.c + hybris/tests/test_hwcomposer.cpp +Copyright: 2012, Carsten Munk +License: Apache-2.0 + +Files: hybris/tests/test_egl_configs.c +Copyright: 2013, Thomas Perl +License: Apache-2.0 + +Files: hybris/tests/test_gps.c + hybris/tests/test_nfc.c + hybris/tests/test_vibrator.c +Copyright: 2012-2014, Jolla Ltd +License: Apache-2.0 + +Files: hybris/tests/test_lights.c + hybris/tests/test_sensors.c + hybris/tests/test_ui.c +Copyright: 2012, 2013, Simon Busch +License: Apache-2.0 + +Files: hybris/ui/* +Copyright: 2012, 2013, Simon Busch +License: Apache-2.0 + +Files: hybris/utils/* +Copyright: 2013, 2014, Canonical Ltd + 2008, The Android Open Source Project +License: Apache-2.0 + +Files: hybris/vibrator/* +Copyright: 2012-2014, Jolla Ltd +License: Apache-2.0 + +Files: utils/* +Copyright: 2013, Jolla Ltd + 2012, Thomas Perl ; 2012-10-19 libhybris version: +License: BSD-2-clause + +Files: utils/generate_wrapper_macros.py +Copyright: 2013, Jolla Ltd +License: BSD-2-clause + +Files: utils/load_sym_files.py +Copyright: 2013, Adrian Negreanu +License: GPL-3+ + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + . + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see . + . + On Debian systems, the full text of the GNU Lesser General Public + License version 3 can be found in the file + `/usr/share/common-licenses/GPL-3'. + +License: Apache-2.0 + 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. + +License: BSD-2-clause + 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. + +License: Expat + The MIT License + . + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated + documentation files (the "Software"), to deal in the Software + without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to + whom the Software is furnished to do so, subject to the + following conditions: + . + The above copyright notice and this permission notice shall + be included in all copies or substantial portions of the + Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT + WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + +License: ISC + 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. + +License: LGPL-2+ + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + . + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA + . + On Debian systems, the full text of the GNU Lesser General Public + License version 2 can be found in the file + `/usr/share/common-licenses/LGPL-2'. + +License: LGPL-2.1 + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation, version 2.1 + of the License. + . + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + . + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301 USA + . + On Debian systems, the full text of the GNU Lesser General Public + License version 2.1 can be found in the file + `/usr/share/common-licenses/LGPL-2.1'. + +License: X11/MIT + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +License: SGI-2.0 + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished + to do so, subject to the following conditions: + . + The above copyright notice including the dates of first publication and either + this permission notice or a reference to http://oss.sgi.com/projects/FreeB/ + shall be included in all copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + . + Except as contained in this notice, the name of Silicon Graphics, Inc. shall + not be used in advertising or otherwise to promote the sale, use or other + dealings in this Software without prior written authorization from Silicon + Graphics, Inc. diff --git a/debian/getprop.1 b/debian/getprop.1 new file mode 100644 index 000000000..851fe9d96 --- /dev/null +++ b/debian/getprop.1 @@ -0,0 +1,24 @@ +.TH GETPROP 1 "July 1, 2013" +.SH NAME +getprop \- get property via the android property service +.SH SYNOPSIS +.B getprop +.RI "[property] [default]" +.SH DESCRIPTION +.PP +\fBgetprop\fP is an android utility to retrive a property via the android property service. + +All properties and values are retrieved when there's no argument. + +.SH OPTIONS +.TP +.B property +Name of the property to be retrieved +.TP +.B default +Default property value in case it's not available in the android property service +.SH AUTHOR +getprop is originally available in the Android AOSP project. +.PP +This manual page was written by Ricardo Salveti de Araujo , +for the Debian project (and may be used by others). diff --git a/debian/libandroid-properties-dev.install b/debian/libandroid-properties-dev.install new file mode 100644 index 000000000..25ed67784 --- /dev/null +++ b/debian/libandroid-properties-dev.install @@ -0,0 +1,3 @@ +usr/lib/*/libandroid-properties.so +usr/lib/*/pkgconfig/libandroid-properties.pc +usr/include/hybris/properties diff --git a/debian/libandroid-properties1.install b/debian/libandroid-properties1.install new file mode 100644 index 000000000..5640d04c1 --- /dev/null +++ b/debian/libandroid-properties1.install @@ -0,0 +1 @@ +usr/lib/*/libandroid-properties.so.* diff --git a/debian/libhardware-dev.install b/debian/libhardware-dev.install new file mode 100644 index 000000000..cfbd33ff9 --- /dev/null +++ b/debian/libhardware-dev.install @@ -0,0 +1,2 @@ +usr/lib/*/libhardware.so +usr/lib/*/pkgconfig/libhardware.pc diff --git a/debian/libhardware2.install b/debian/libhardware2.install new file mode 100644 index 000000000..44f5dca99 --- /dev/null +++ b/debian/libhardware2.install @@ -0,0 +1 @@ +usr/lib/*/libhardware.so.* diff --git a/debian/libhybris-common-dev.install b/debian/libhybris-common-dev.install new file mode 100644 index 000000000..612e3e76d --- /dev/null +++ b/debian/libhybris-common-dev.install @@ -0,0 +1 @@ +usr/lib/*/libhybris-common.so diff --git a/debian/libhybris-common1.install b/debian/libhybris-common1.install new file mode 100644 index 000000000..a2bd2a7ef --- /dev/null +++ b/debian/libhybris-common1.install @@ -0,0 +1,2 @@ +usr/lib/*/libhybris-common.so.* +usr/lib/*/libhybris/linker/*.so diff --git a/debian/libhybris-dev.install b/debian/libhybris-dev.install new file mode 100644 index 000000000..2a0b4fb74 --- /dev/null +++ b/debian/libhybris-dev.install @@ -0,0 +1,28 @@ +usr/lib/*/libhybris-eglplatformcommon.so +usr/lib/*/libhybris-hwcomposerwindow.so +usr/lib/*/libsync.so +usr/lib/*/libui.so +usr/lib/*/libsf.so +usr/lib/*/libis.so +usr/lib/*/libcamera.so +usr/lib/*/libwifi.so +usr/lib/*/libnfc_nxp.so +usr/lib/*/libvibrator.so +usr/lib/*/pkgconfig/hwcomposer-egl.pc +usr/lib/*/pkgconfig/hybris-egl-platform.pc +usr/lib/*/pkgconfig/libis.pc +usr/lib/*/pkgconfig/libcamera.pc +usr/lib/*/pkgconfig/libwifi.pc +usr/lib/*/pkgconfig/libvibrator.pc +usr/lib/*/pkgconfig/libnfc_nxp.pc +usr/lib/*/pkgconfig/libsf.pc +usr/lib/*/pkgconfig/libsync.pc +usr/include/hybris/input +usr/include/hybris/camera +usr/include/hybris/eglplatformcommon +usr/include/hybris/surface_flinger +usr/include/hybris/ui +usr/include/hybris/eglplatformcommon +usr/include/hybris/hwcomposerwindow +usr/include/hybris/dlfcn +usr/include/hybris/common diff --git a/debian/libhybris-test.install b/debian/libhybris-test.install new file mode 100644 index 000000000..04baf6a41 --- /dev/null +++ b/debian/libhybris-test.install @@ -0,0 +1 @@ +usr/bin/test_* diff --git a/debian/libhybris-utils.install b/debian/libhybris-utils.install new file mode 100644 index 000000000..fa2001275 --- /dev/null +++ b/debian/libhybris-utils.install @@ -0,0 +1,3 @@ +usr/bin/getprop +usr/bin/setprop +utils/load_sym_files.py usr/share/libhybris/gdb/ diff --git a/debian/libhybris-utils.manpages b/debian/libhybris-utils.manpages new file mode 100644 index 000000000..6cb23c011 --- /dev/null +++ b/debian/libhybris-utils.manpages @@ -0,0 +1,2 @@ +debian/getprop.1 +debian/setprop.1 diff --git a/debian/libhybris.dirs.in b/debian/libhybris.dirs.in new file mode 100644 index 000000000..1d782245f --- /dev/null +++ b/debian/libhybris.dirs.in @@ -0,0 +1,2 @@ +usr/lib/arm-linux-gnueabihf/libhybris +#PKGLIBDIR# diff --git a/debian/libhybris.install.in b/debian/libhybris.install.in new file mode 100644 index 000000000..60e1c1744 --- /dev/null +++ b/debian/libhybris.install.in @@ -0,0 +1,15 @@ +usr/lib/*/libhybris-eglplatformcommon.so.* +usr/lib/*/libhybris-hwcomposerwindow.so.* +usr/lib/*/libsync.so.* +usr/lib/*/libui.so.* +usr/lib/*/libsf.so.* +usr/lib/*/libis.so.* +usr/lib/*/libcamera.so.* +usr/lib/*/libwifi.so.* +usr/lib/*/libnfc_nxp.so.* +usr/lib/*/libvibrator.so.* +usr/lib/*/libhybris/*.so +usr/lib/*/libwayland-egl.so.* #PKGLIBDIR# +usr/lib/*/libEGL.so.* #PKGLIBDIR# +usr/lib/*/libGLESv2.so.* #PKGLIBDIR# +usr/lib/*/libGLESv1_CM.so.* #PKGLIBDIR# diff --git a/debian/libhybris.links.in b/debian/libhybris.links.in new file mode 100644 index 000000000..12590e774 --- /dev/null +++ b/debian/libhybris.links.in @@ -0,0 +1 @@ +#LIBDIR#/libhybris-common.so.1 #LIBDIR#/libhybris_ics.so diff --git a/debian/libhybris.postinst.in b/debian/libhybris.postinst.in new file mode 100644 index 000000000..da45afb7e --- /dev/null +++ b/debian/libhybris.postinst.in @@ -0,0 +1,21 @@ +#!/bin/sh +# Copyright (C) 2007 Mario Limonciello +# Copyright (C) 2009-2011 Canonical Ltd. + +set -e + +PACKAGE_NAME=#DRIVERNAME# +ARCH=`dpkg --print-architecture` + +if [ "$1" = "configure" ]; then + + update-alternatives --force \ + --install /#SYSCONFDIR#/ld.so.conf.d/#DEB_HOST_MULTIARCH#_EGL.conf #DEB_HOST_MULTIARCH#_egl_conf /#LDSOCONF# #ALTPRIORITY# + + # ldconfig needs to be run immediately as we're changing /etc/ld.so.conf.d/ with + # alternatives. + LDCONFIG_NOTRIGGER=y ldconfig + +fi + +#DEBHELPER# diff --git a/debian/libhybris.postrm.in b/debian/libhybris.postrm.in new file mode 100644 index 000000000..f975b6fd8 --- /dev/null +++ b/debian/libhybris.postrm.in @@ -0,0 +1,47 @@ +#! /bin/sh +# +# see: dh_installdeb(1) +# +# Copyright (C) 2007 Mario Limonciello +# Copyright (C) 2009-2011 Canonical Ltd. + +set -e + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' overwrit>r> +# for details, see /usr/share/doc/packaging-manual/ + +PKGNAME=#DRIVERNAME# + +case "$1" in + remove|purge) + + if [ "$1" = "purge" ]; then + rm -Rf /#PKGLIBDIR# + else + # This will preserve the etc directory + rm -f /#PKGLIBDIR#/* 2>/dev/null || true + fi + + ;; + + upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 0 + +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# diff --git a/debian/libhybris.prerm.in b/debian/libhybris.prerm.in new file mode 100644 index 000000000..16d94e51c --- /dev/null +++ b/debian/libhybris.prerm.in @@ -0,0 +1,19 @@ +#!/bin/sh +# +# Copyright (C) 2007 Mario Limonciello +# Copyright (C) 2009-2011 Canonical Ltd. + +set -e + +PACKAGE_NAME=#DRIVERNAME# + +case "$1" in + remove) + update-alternatives --remove #DEB_HOST_MULTIARCH#_egl_conf /#LDSOCONF# + + # explicit ldconfig due to alternatives + LDCONFIG_NOTRIGGER=y ldconfig + ;; +esac + +#DEBHELPER# diff --git a/debian/libmedia-dev.install b/debian/libmedia-dev.install new file mode 100644 index 000000000..d75bd811c --- /dev/null +++ b/debian/libmedia-dev.install @@ -0,0 +1,3 @@ +usr/lib/*/libmedia.so +usr/lib/*/pkgconfig/libmedia.pc +usr/include/hybris/media diff --git a/debian/libmedia1.install b/debian/libmedia1.install new file mode 100644 index 000000000..a1562daf8 --- /dev/null +++ b/debian/libmedia1.install @@ -0,0 +1 @@ +usr/lib/*/libmedia.so.* diff --git a/debian/rules b/debian/rules new file mode 100755 index 000000000..0716d9ffa --- /dev/null +++ b/debian/rules @@ -0,0 +1,156 @@ +#!/usr/bin/make -f + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# Package names +PKG_driver := libhybris +PKG_driver_dev := libhybris-dev +PKG_driver_dbg := libhybris-dbg +PKG_version := $(shell dpkg-parsechangelog | sed -n 's/^Version: //p') +PKG_source := $(shell dpkg-parsechangelog | sed -n 's/^Source: //p') +PKG_distro := $(shell dpkg-parsechangelog | sed -n 's/^Distribution: //p') +UPS_version := $(shell echo '$(PKG_version)' | sed 's/.*://; s/-[^-]*$$//') +GIT_rev := $(shell echo '$(UPS_version)' | sed 's/.*+//') + +DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) +DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +ifeq ($(PKG_distro),vivid) +# For vivid we still depend on GCC 4.7 as this seems to be still +# required to workaround ABI issues. +export CC=gcc-4.7 +export CXX=g++-4.7 +EXTRA_BUILD_DEPENDS = gcc-4.7, g++-4.7, +endif + +# Strong needs at least gcc 4.9 +export DEB_BUILD_MAINT_OPTIONS=hardening=-stackprotectorstrong + +ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE)) + CC :=$(DEB_HOST_GNU_TYPE)-$(CC) + CXX :=$(DEB_HOST_GNU_TYPE)-$(CXX) +endif + +# Priority of the alternatives +alt_priority := 400 + +# Directory naming schemes +PKG_dirname := $(PKG_driver)-egl +bindir := usr/bin +datadir := usr/share +libdir := usr/lib/$(DEB_HOST_MULTIARCH) +includedir := usr/include +sysconfdir := etc +PKG_libdir := $(libdir)/$(PKG_dirname) +PKG_configdir := $(PKG_libdir) +ld_so_conf_dir := $(PKG_configdir) +ld_so_conf_file := ld.so.conf +alt_ld_so_conf_file := alt_ld.so.conf +ld_so_conf_path := $(ld_so_conf_dir)/$(ld_so_conf_file) +alt_ld_so_conf_path := $(ld_so_conf_dir)/$(alt_ld_so_conf_file) + +.PHONY: debian/control +debian/control: debian/control.in + if [ "$(EXTRA_BUILD_DEPENDS)" = "" ] ; then \ + sed -e '/@EXTRA_BUILD_DEPENDS@/,+0d' \ + debian/control.in > debian/control ; \ + else \ + sed -e "s/@EXTRA_BUILD_DEPENDS@/$(EXTRA_BUILD_DEPENDS)/" \ + debian/control.in > debian/control ; \ + fi + +override_dh_auto_clean: debian/control + dh_auto_clean + +# --remote doesn't work with github so this needs to be run from a local checkout +get-packaged-orig-source: + rm -rf $(PKG_source)-$(UPS_version) + rm -f $(PKG_source)-$(UPS_version).orig.tar.gz + git clone https://github.com/libhybris/libhybris.git $(PKG_source)-$(UPS_version) + cd $(PKG_source)-$(UPS_version) && git archive \ + --format tar \ + --prefix $(PKG_source)-$(UPS_version)/ \ + $(GIT_rev) \ + | gzip >../$(PKG_source)_$(UPS_version).orig.tar.gz + rm -rf $(PKG_source)-$(UPS_version) + +ANDROID_HEADERS_PATH = /usr/include/android +DEFAULT_CONFIGURATION = \ + --enable-wayland \ + --with-android-headers=$(ANDROID_HEADERS_PATH) \ + --enable-property-cache +ARCH_CONFIGURATION = + +ifeq ($(DEB_HOST_ARCH),$(findstring $(DEB_HOST_ARCH), armhf)) +ARCH_CONFIGURATION = \ + --enable-arch=arm \ + --enable-mali-quirks \ + --enable-experimental +# We enable the linker selection overrides here as we want to stay +# with the jb linker on a range of selected production devices to +# not cause any extra risk for regressions on them. They will +# migrate to a newer linker version when ported to arm64. +ARCH_CONFIGURATION += \ + --enable-ubuntu-linker-overrides +endif +ifeq ($(DEB_HOST_ARCH),$(findstring $(DEB_HOST_ARCH), arm64)) +ARCH_CONFIGURATION = \ + --enable-arch=arm64 \ + --enable-mali-quirks \ + --enable-experimental +endif +ifeq ($(DEB_HOST_ARCH),$(findstring $(DEB_HOST_ARCH), i386)) +ARCH_CONFIGURATION = \ + --enable-arch=x86 +endif +ifeq ($(DEB_HOST_ARCH),$(findstring $(DEB_HOST_ARCH), amd64)) +ARCH_CONFIGURATION = \ + --enable-arch=x86 +endif + +override_dh_auto_configure: + dh_auto_configure --sourcedirectory=hybris -- \ + $(DEFAULT_CONFIGURATION) \ + $(ARCH_CONFIGURATION) + +override_dh_install: + # Fill in important variables + for i in $(PKG_driver).dirs \ + $(PKG_driver).install \ + $(PKG_driver).links \ + $(PKG_driver).postinst \ + $(PKG_driver).postrm \ + $(PKG_driver).prerm; do \ + sed -e "s|#LIBDIR#|$(libdir)|g" \ + -e "s|#BINDIR#|$(bindir)|g" \ + -e "s|#SYSCONFDIR#|$(sysconfdir)|g" \ + -e "s|#LDSOCONF#|$(ld_so_conf_path)|g" \ + -e "s|#ALTLDSOCONF#|$(alt_ld_so_conf_path)|g" \ + -e "s|#ALTPRIORITY#|$(alt_priority)|g" \ + -e "s|#DATADIR#|$(datadir)|g" \ + -e "s|#PKGCONFIGDIR#|$(PKG_configdir)|g" \ + -e "s|#PKGLIBDIR#|$(PKG_libdir)|g" \ + -e "s|#DRIVERNAME#|$(PKG_driver)|g" \ + -e "s|#DRIVERSRCNAME#|$(PKG_source)|g" \ + -e "s|#VERSION#|$(PKG_version)|g" \ + -e "s|#INCLUDEDIR#|$(includedir)|g" \ + -e "s|#DEB_HOST_MULTIARCH#|$(DEB_HOST_MULTIARCH)|g" \ + debian/$$i.in > debian/$$i; \ + done + + dh_install + + # ld.so.conf + echo "/$(PKG_libdir)" > "$(CURDIR)/debian/$(PKG_driver)/$(ld_so_conf_path)" + + # empty ld.so.conf for the fake multi-arch alternative + echo "" > "$(CURDIR)/debian/$(PKG_driver)/$(alt_ld_so_conf_path)" + +override_dh_autoreconf: + NOCONFIGURE=1 dh_autoreconf ./hybris/autogen.sh + +%: + dh $@ --with quilt,autoreconf --sourcedirectory=hybris diff --git a/debian/setprop.1 b/debian/setprop.1 new file mode 100644 index 000000000..9d5ced19d --- /dev/null +++ b/debian/setprop.1 @@ -0,0 +1,21 @@ +.TH SETPROP 1 "July 1, 2013" +.SH NAME +setprop \- set property via the android property service +.SH SYNOPSIS +.B setprop +.RI "property value" +.SH DESCRIPTION +.PP +\fBsetprop\fP is an android utility to set up a property via the android property service. +.SH OPTIONS +.TP +.B property +Name of the property to be set +.TP +.B value +Value of the property (string, numbers, etc) +.SH AUTHOR +setprop is originally available in the Android AOSP project. +.PP +This manual page was written by Ricardo Salveti de Araujo , +for the Debian project (and may be used by others). diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 000000000..163aaf8d8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/debian/source/options b/debian/source/options new file mode 100644 index 000000000..7423a2df3 --- /dev/null +++ b/debian/source/options @@ -0,0 +1 @@ +single-debian-patch diff --git a/debian/source/patch-header b/debian/source/patch-header new file mode 100644 index 000000000..245b1be92 --- /dev/null +++ b/debian/source/patch-header @@ -0,0 +1,10 @@ +Subject: Collected Debian patches for libhybris +Author: Ricardo Salveti de Araujo + +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. diff --git a/hybris/Makefile.am b/hybris/Makefile.am index 40ca6cc73..906140e4b 100644 --- a/hybris/Makefile.am +++ b/hybris/Makefile.am @@ -6,7 +6,7 @@ endif if HAS_ANDROID_5_0_0 SUBDIRS += libsync endif -SUBDIRS += egl glesv1 glesv2 vibrator +SUBDIRS += egl glesv1 glesv2 ui sf input camera vibrator media wifi if HAS_LIBNFC_NXP_HEADERS SUBDIRS += libnfc_nxp libnfc_ndef_nxp diff --git a/hybris/README b/hybris/README index e69de29bb..39d053077 100644 --- a/hybris/README +++ b/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. diff --git a/hybris/camera/Makefile.am b/hybris/camera/Makefile.am new file mode 100644 index 000000000..63aec2e81 --- /dev/null +++ b/hybris/camera/Makefile.am @@ -0,0 +1,17 @@ +lib_LTLIBRARIES = \ + libcamera.la + +libcamera_la_SOURCES = camera.c +libcamera_la_CFLAGS = -I$(top_srcdir)/include $(ANDROID_HEADERS_CFLAGS) +if WANT_TRACE +libcamera_la_CFLAGS += -DDEBUG +endif +if WANT_DEBUG +libcamera_la_CFLAGS += -ggdb -O0 +endif +libcamera_la_LDFLAGS = \ + $(top_builddir)/common/libhybris-common.la \ + -version-info "1":"0":"0" + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libcamera.pc diff --git a/hybris/camera/camera.c b/hybris/camera/camera.c new file mode 100644 index 000000000..f51f70b6c --- /dev/null +++ b/hybris/camera/camera.c @@ -0,0 +1,148 @@ +/* + * 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: Michael Frey + * Ricardo Salveti de Araujo + */ + +#include +#include +#include + +#include +#include +#include +#include + +#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*); +HYBRIS_IMPLEMENT_FUNCTION1(camera, int, android_camera_unlock, struct CameraControl*); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_delete, struct CameraControl*); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_dump_parameters, + struct CameraControl*); + +// Setters +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_effect_mode, + struct CameraControl*, EffectMode); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_flash_mode, + struct CameraControl*, FlashMode); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_white_balance_mode, + struct CameraControl*, WhiteBalanceMode); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_scene_mode, + 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, + struct CameraControl*, int32_t); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_preview_texture, + struct CameraControl*, int); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_preview_surface, + struct CameraControl*, struct SfSurface*); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_set_focus_region, + 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, + struct CameraControl*, EffectMode*); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_get_flash_mode, + struct CameraControl*, FlashMode*); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_get_white_balance_mode, + struct CameraControl*, WhiteBalanceMode*); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_get_scene_mode, + struct CameraControl*, SceneMode*); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_get_auto_focus_mode, + struct CameraControl*, AutoFocusMode*); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_get_max_zoom, + 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, + struct CameraControl*, int*, int*); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_get_preview_fps, + struct CameraControl*, int*); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_get_preview_texture_transformation, + 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*); + +HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_start_preview, struct CameraControl*); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_stop_preview, struct CameraControl*); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_start_autofocus, struct CameraControl*); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(camera, android_camera_stop_autofocus, struct CameraControl*); + +HYBRIS_IMPLEMENT_VOID_FUNCTION2(camera, android_camera_start_zoom, struct CameraControl*, int32_t); +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); diff --git a/hybris/camera/libcamera.pc.in b/hybris/camera/libcamera.pc.in new file mode 100644 index 000000000..be38931a2 --- /dev/null +++ b/hybris/camera/libcamera.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=@libdir@ +includedir=@includedir@ + +Name: hybris-camera +Description: libhybris camera library +Version: @VERSION@ +Libs: -L${libdir} -lhybris-common -lcamera +Cflags: -I${includedir} diff --git a/hybris/common/Makefile.am b/hybris/common/Makefile.am index 2c795b359..867627ed7 100644 --- a/hybris/common/Makefile.am +++ b/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)" diff --git a/hybris/common/gingerbread/Makefile.am b/hybris/common/gingerbread/Makefile.am deleted file mode 100644 index f265879a6..000000000 --- a/hybris/common/gingerbread/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -if WANT_ARCH_ARM -ARCHFLAGS = -DHAVE_ARM_TLS_REGISTER -DANDROID_ARM_LINKER -endif - -if WANT_ARCH_X86 -ARCHFLAGS = -DANDROID_X86_LINKER -endif - -noinst_LTLIBRARIES = \ - libandroid-linker.la -libandroid_linker_la_SOURCES = \ - dlfcn.c \ - linker.c \ - linker_environ.c \ - linker_format.c \ - rt.c -libandroid_linker_la_CFLAGS = \ - -I$(top_srcdir)/include \ - $(ANDROID_HEADERS_CFLAGS) \ - -I$(top_srcdir)/common \ - -DLINKER_TEXT_BASE=0xB0000100 \ - -DLINKER_AREA_SIZE=0x01000000 \ - $(ARCHFLAGS) - -if WANT_DEBUG -libandroid_linker_la_CFLAGS += -DLINKER_DEBUG=1 -else -libandroid_linker_la_CFLAGS += -DLINKER_DEBUG=0 -endif diff --git a/hybris/common/gingerbread/NOTICE b/hybris/common/gingerbread/NOTICE deleted file mode 100644 index c5b1efa7a..000000000 --- a/hybris/common/gingerbread/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - Copyright (c) 2005-2008, 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. - - 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. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - diff --git a/hybris/common/gingerbread/README.TXT b/hybris/common/gingerbread/README.TXT deleted file mode 100644 index f920b97bb..000000000 --- a/hybris/common/gingerbread/README.TXT +++ /dev/null @@ -1,144 +0,0 @@ -Android Dynamic Linker Design Notes -=================================== - -Introduction: -------------- - -This document provides several notes related to the design of the Android -dynamic linker. - - -Prelinking: ------------ - -System libraries in Android are internally prelinked, which means that -any internal relocations within them are stripped from the corresponding -shared object, in order to reduce size and speed up loading. - -Such libraries can only be loaded at the very specific virtual memory address -they have been prelinked to (during the build process). The list of prelinked -system libraries and their corresponding virtual memory address is found in -the file: - - build/core/prelink-linux-.map - -It should be updated each time a new system library is added to the -system. - -The prelink step happens at build time, and uses the 'soslim' and 'apriori' -tools: - - - 'apriori' is the real prelink tool which removes relocations from the - shared object, however, it must be given a list of symbols to remove - from the file. - - - 'soslim' is used to find symbols in an executable ELF file - and generate a list that can be passed to 'apriori'. - -By default, these tools are only used to remove internal symbols from -libraries, though they have been designed to allow more aggressive -optimizations (e.g. 'global' prelinking and symbol stripping, which -prevent replacing individual system libraries though). - -You can disable prelinking at build time by modifying your Android.mk with -a line like: - - LOCAL_PRELINK_MODULE := false - - -Initialization and Termination functions: ------------------------------------------ - -The Unix Sys V Binary Interface standard states that an -executable can have the following entries in its .dynamic -section: - - DT_INIT - Points to the address of an initialization function - that must be called when the file is loaded. - - DT_INIT_ARRAY - Points to an array of function addresses that must be - called, in-order, to perform initialization. Some of - the entries in the array can be 0 or -1, and should - be ignored. - - Note: this is generally stored in a .init_array section - - DT_INIT_ARRAYSZ - The size of the DT_INITARRAY, if any - - DT_FINI - Points to the address of a finalization function which - must be called when the file is unloaded or the process - terminated. - - DT_FINI_ARRAY - Same as DT_INITARRAY but for finalizers. Note that the - functions must be called in reverse-order though - - Note: this is generally stored in a .fini_array section - - DT_FINI_ARRAYSZ - Size of FT_FINIARRAY - - DT_PREINIT_ARRAY - An array similar to DT_INIT_ARRAY which must *only* be - present in executables, not shared libraries, which contains - a list of functions that need to be called before any other - initialization function (i.e. DT_INIT and/or DT_INIT_ARRAY) - in the executable or any of its libraries. - - Note: this is generally stored in a .preinit_array section - - DT_PREINIT_ARRAYSZ - The size of DT_PREINIT_ARRAY - -If both a DT_INIT and DT_INITARRAY entry are present, the DT_INIT -function must be called before the DT_INITARRAY functions. - -Consequently, the DT_FINIARRAY must be parsed in reverse order before -the DT_FINI function, if both are available. - -Note that the implementation of static C++ constructors is very -much processor dependent, and may use different ELF sections. - -On the ARM (see "C++ ABI for ARM" document), the static constructors -must be called explicitly from the DT_INIT_ARRAY, and each one of them -shall register a destructor by calling the special __eabi_atexit() -function (provided by the C library). The DT_FINI_ARRAY is not used -by static C++ destructors. - -On x86, the lists of constructors and destructors are placed in special -sections named ".ctors" and ".dtors", and the DT_INIT / DT_FINI functions -are in charge of calling them explicitly. - - -Debugging: ----------- - -It is possible to enable debug output in the dynamic linker. To do so, -follow these steps: - -1/ Modify the line in Android.mk that says: - - LOCAL_CFLAGS += -DLINKER_DEBUG=0 - - Into the following: - - LOCAL_CFLAGS += -DLINKER_DEBUG=1 - -2/ Force-rebuild the dynamic linker: - - cd bionic/linker - mm -B - -3/ Rebuild a new system image. - -You can increase the verbosity of debug traces by defining the DEBUG -environment variable to a numeric value from 0 to 2. 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 in "linker_debug.h". diff --git a/hybris/common/gingerbread/bionic_tls.h b/hybris/common/gingerbread/bionic_tls.h deleted file mode 100644 index 008fd2ff7..000000000 --- a/hybris/common/gingerbread/bionic_tls.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * 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 _SYS_TLS_H -#define _SYS_TLS_H - -#include - -__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). - **/ - -/* maximum number of elements in the TLS array */ -#define BIONIC_TLS_SLOTS 64 - -/* note that slot 0, called TLS_SLOT_SELF must point to itself. - * this is required to implement thread-local storage with the x86 - * Linux kernel, that reads the TLS from fs:[0], where 'fs' is a - * thread-specific segment descriptor... - */ - -/* Well known TLS slots */ -#define TLS_SLOT_SELF 0 -#define TLS_SLOT_THREAD_ID 1 -#define TLS_SLOT_ERRNO 2 - -#define TLS_SLOT_OPENGL_API 3 -#define TLS_SLOT_OPENGL 4 - -/* 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. - */ -#define TLS_SLOT_BIONIC_PREINIT (TLS_SLOT_ERRNO+1) - -/* small technical note: it is not possible to call pthread_setspecific - * on keys that are <= TLS_SLOT_MAX_WELL_KNOWN, which is why it is set to - * TLS_SLOT_ERRNO. - * - * later slots like TLS_SLOT_OPENGL are pre-allocated through the use of - * TLS_DEFAULT_ALLOC_MAP. this means that there is no need to use - * pthread_key_create() to initialize them. on the other hand, there is - * no destructor associated to them (we might need to implement this later) - */ -#define TLS_SLOT_MAX_WELL_KNOWN TLS_SLOT_ERRNO - -#define TLS_DEFAULT_ALLOC_MAP 0x0000001F - -/* set the Thread Local Storage, must contain at least BIONIC_TLS_SLOTS pointers */ -extern void __init_tls(void** tls, void* thread_info); - -/* syscall only, do not call directly */ -extern int __set_tls(void *ptr); - -/* get the TLS */ -#ifdef __arm__ -/* The standard way to get the TLS is to call a kernel helper - * function (i.e. a function provided at a fixed address in a - * "magic page" mapped in all user-space address spaces ), which - * contains the most appropriate code path for the target device. - * - * However, for performance reasons, we're going to use our own - * machine code for the system's C shared library. - * - * We cannot use this optimization in the static version of the - * C library, because we don't know where the corresponding code - * is going to run. - */ -# ifdef LIBC_STATIC - -/* Use the kernel helper in static C library. */ - typedef volatile void* (__kernel_get_tls_t)(void); -# define __get_tls() (*(__kernel_get_tls_t *)0xffff0fe0)() - -# else /* !LIBC_STATIC */ -/* Use optimized code path. - * Note that HAVE_ARM_TLS_REGISTER is build-specific - * (it must match your kernel configuration) - */ -# ifdef HAVE_ARM_TLS_REGISTER - /* We can read the address directly from a coprocessor - * register, which avoids touching the data cache - * completely. - */ -# define __get_tls() \ - ({ register unsigned int __val asm("r0"); \ - asm ("mrc p15, 0, r0, c13, c0, 3" : "=r"(__val) ); \ - (volatile void*)__val; }) -# else /* !HAVE_ARM_TLS_REGISTER */ - /* The kernel provides the address of the TLS at a fixed - * address of the magic page too. - */ -# define __get_tls() ( *((volatile void **) 0xffff0ff0) ) -# endif -# endif /* !LIBC_STATIC */ -#else /* !ARM */ -extern void* __get_tls( void ); -#endif /* !ARM */ - -/* return the stack base and size, used by our malloc debugger */ -extern void* __get_stack_base(int *p_stack_size); - -__END_DECLS - -#endif /* _SYS_TLS_H */ diff --git a/hybris/common/gingerbread/debugger.c b/hybris/common/gingerbread/debugger.c deleted file mode 100644 index a84dc779e..000000000 --- a/hybris/common/gingerbread/debugger.c +++ /dev/null @@ -1,241 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "linker.h" - -#include -#include - -extern int tgkill(int tgid, int tid, int sig); - -void notify_gdb_of_libraries(); - -#define DEBUGGER_SOCKET_NAME "android:debuggerd" - -typedef enum { - // dump a crash - DEBUGGER_ACTION_CRASH, - // dump a tombstone file - DEBUGGER_ACTION_DUMP_TOMBSTONE, - // dump a backtrace only back to the socket - DEBUGGER_ACTION_DUMP_BACKTRACE, -} debugger_action_t; - -/* message sent over the socket */ -typedef struct { - debugger_action_t action; - pid_t tid; -} debugger_msg_t; - -#define RETRY_ON_EINTR(ret,cond) \ - do { \ - ret = (cond); \ - } while (ret < 0 && errno == EINTR) - -// see man(2) prctl, specifically the section about PR_GET_NAME -#define MAX_TASK_NAME_LEN (16) - -static int socket_abstract_client(const char *name, int type) -{ - struct sockaddr_un addr; - size_t namelen; - socklen_t alen; - int s, err; - - namelen = strlen(name); - - // Test with length +1 for the *initial* '\0'. - if ((namelen + 1) > sizeof(addr.sun_path)) { - errno = EINVAL; - return -1; - } - - /* This is used for abstract socket namespace, we need - * an initial '\0' at the start of the Unix socket path. - * - * Note: The path in this case is *not* supposed to be - * '\0'-terminated. ("man 7 unix" for the gory details.) - */ - memset (&addr, 0, sizeof addr); - addr.sun_family = AF_LOCAL; - addr.sun_path[0] = 0; - memcpy(addr.sun_path + 1, name, namelen); - - alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; - - s = socket(AF_LOCAL, type, 0); - if(s < 0) return -1; - - RETRY_ON_EINTR(err,connect(s, (struct sockaddr *) &addr, alen)); - if (err < 0) { - close(s); - s = -1; - } - - return s; -} - -#include "linker_format.h" -#include <../libc/private/logd.h> - -/* - * Writes a summary of the signal to the log file. - * - * We could be here as a result of native heap corruption, or while a - * mutex is being held, so we don't want to use any libc functions that - * could allocate memory or hold a lock. - */ -static void logSignalSummary(int signum, const siginfo_t* info) -{ - char buffer[128]; - char threadname[MAX_TASK_NAME_LEN + 1]; // one more for termination - - char* signame; - switch (signum) { - case SIGILL: signame = "SIGILL"; break; - case SIGABRT: signame = "SIGABRT"; break; - case SIGBUS: signame = "SIGBUS"; break; - case SIGFPE: signame = "SIGFPE"; break; - case SIGSEGV: signame = "SIGSEGV"; break; - case SIGSTKFLT: signame = "SIGSTKFLT"; break; - case SIGPIPE: signame = "SIGPIPE"; break; - default: signame = "???"; break; - } - - if (prctl(PR_GET_NAME, (unsigned long)threadname, 0, 0, 0) != 0) { - strcpy(threadname, ""); - } else { - // short names are null terminated by prctl, but the manpage - // implies that 16 byte names are not. - threadname[MAX_TASK_NAME_LEN] = 0; - } - format_buffer(buffer, sizeof(buffer), - "Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)", - signum, signame, info->si_addr, info->si_code, gettid(), threadname); - - __libc_android_log_write(ANDROID_LOG_FATAL, "libc", buffer); -} - -/* - * Catches fatal signals so we can ask debuggerd to ptrace us before - * we crash. - */ -void debugger_signal_handler(int n, siginfo_t* info, void* unused) -{ - char msgbuf[128]; - unsigned tid; - int s; - - logSignalSummary(n, info); - - tid = gettid(); - s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM); - - if (s >= 0) { - /* debugger knows our pid from the credentials on the - * local socket but we need to tell it our tid. It - * is paranoid and will verify that we are giving a tid - * that's actually in our process - */ - int ret; - debugger_msg_t msg; - msg.action = DEBUGGER_ACTION_CRASH; - msg.tid = tid; - RETRY_ON_EINTR(ret, write(s, &msg, sizeof(msg))); - if (ret == sizeof(msg)) { - /* if the write failed, there is no point to read on - * the file descriptor. */ - RETRY_ON_EINTR(ret, read(s, &tid, 1)); - int savedErrno = errno; - notify_gdb_of_libraries(); - errno = savedErrno; - } - - if (ret < 0) { - /* read or write failed -- broken connection? */ - format_buffer(msgbuf, sizeof(msgbuf), - "Failed while talking to debuggerd: %s", strerror(errno)); - __libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf); - } - - close(s); - } else { - /* socket failed; maybe process ran out of fds */ - format_buffer(msgbuf, sizeof(msgbuf), - "Unable to open connection to debuggerd: %s", strerror(errno)); - __libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf); - } - - /* remove our net so we fault for real when we return */ - signal(n, SIG_DFL); - - /* - * These signals are not re-thrown when we resume. This means that - * crashing due to (say) SIGPIPE doesn't work the way you'd expect it - * to. We work around this by throwing them manually. We don't want - * to do this for *all* signals because it'll screw up the address for - * faults like SIGSEGV. - */ - switch (n) { - case SIGABRT: - case SIGFPE: - case SIGPIPE: - case SIGSTKFLT: - (void) tgkill(getpid(), gettid(), n); - break; - default: // SIGILL, SIGBUS, SIGSEGV - break; - } -} - -void debugger_init() -{ - struct sigaction act; - memset(&act, 0, sizeof(act)); - act.sa_sigaction = debugger_signal_handler; - act.sa_flags = SA_RESTART | SA_SIGINFO; - sigemptyset(&act.sa_mask); - - sigaction(SIGILL, &act, NULL); - sigaction(SIGABRT, &act, NULL); - sigaction(SIGBUS, &act, NULL); - sigaction(SIGFPE, &act, NULL); - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGSTKFLT, &act, NULL); - sigaction(SIGPIPE, &act, NULL); -} diff --git a/hybris/common/gingerbread/dlfcn.c b/hybris/common/gingerbread/dlfcn.c deleted file mode 100644 index 2a6d01c83..000000000 --- a/hybris/common/gingerbread/dlfcn.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * 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. - */ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include "linker.h" -#include "linker_format.h" - -/* This file hijacks the symbols stubbed out in libdl.so. */ - -#define DL_SUCCESS 0 -#define DL_ERR_CANNOT_LOAD_LIBRARY 1 -#define DL_ERR_INVALID_LIBRARY_HANDLE 2 -#define DL_ERR_BAD_SYMBOL_NAME 3 -#define DL_ERR_SYMBOL_NOT_FOUND 4 -#define DL_ERR_SYMBOL_NOT_GLOBAL 5 - -static char dl_err_buf[1024]; -static const char *dl_err_str; - -static const char *dl_errors[] = { - [DL_ERR_CANNOT_LOAD_LIBRARY] = "Cannot load library", - [DL_ERR_INVALID_LIBRARY_HANDLE] = "Invalid library handle", - [DL_ERR_BAD_SYMBOL_NAME] = "Invalid symbol name", - [DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found", - [DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global", -}; - -#define likely(expr) __builtin_expect (expr, 1) -#define unlikely(expr) __builtin_expect (expr, 0) - -pthread_mutex_t dl_lock = PTHREAD_MUTEX_INITIALIZER; - -static void set_dlerror(int err) -{ - format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err], - linker_get_error()); - dl_err_str = (const char *)&dl_err_buf[0]; -}; - -void *android_dlopen(const char *filename, int flag) -{ - soinfo *ret; - - pthread_mutex_lock(&dl_lock); - ret = find_library(filename); - if (unlikely(ret == NULL)) { - set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY); - } else { - call_constructors_recursive(ret); - ret->refcount++; - } - pthread_mutex_unlock(&dl_lock); - return ret; -} - -const char *android_dlerror(void) -{ - const char *tmp = dl_err_str; - dl_err_str = NULL; - return (const char *)tmp; -} - -void *android_dlsym(void *handle, const char *symbol) -{ - soinfo *found; - Elf32_Sym *sym; - unsigned bind; - - pthread_mutex_lock(&dl_lock); - - if(unlikely(handle == 0)) { - set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE); - goto err; - } - if(unlikely(symbol == 0)) { - set_dlerror(DL_ERR_BAD_SYMBOL_NAME); - goto err; - } - - if(handle == RTLD_DEFAULT) { - sym = lookup(symbol, &found, NULL); - } else if(handle == RTLD_NEXT) { - void *ret_addr = __builtin_return_address(0); - soinfo *si = find_containing_library(ret_addr); - - sym = NULL; - if(si && si->next) { - sym = lookup(symbol, &found, si->next); - } - } else { - found = (soinfo*)handle; - sym = lookup_in_library(found, symbol); - } - - if(likely(sym != 0)) { - bind = ELF32_ST_BIND(sym->st_info); - - if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) { - unsigned ret = sym->st_value + found->base; - pthread_mutex_unlock(&dl_lock); - return (void*)ret; - } - - set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL); - } - else - set_dlerror(DL_ERR_SYMBOL_NOT_FOUND); - -err: - pthread_mutex_unlock(&dl_lock); - return 0; -} - -int android_dladdr(const void *addr, Dl_info *info) -{ - int ret = 0; - - pthread_mutex_lock(&dl_lock); - - /* Determine if this address can be found in any library currently mapped */ - soinfo *si = find_containing_library(addr); - - if(si) { - memset(info, 0, sizeof(Dl_info)); - - info->dli_fname = si->name; - 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); - - if(sym != NULL) { - info->dli_sname = si->strtab + sym->st_name; - info->dli_saddr = (void*)(si->base + sym->st_value); - } - - ret = 1; - } - - pthread_mutex_unlock(&dl_lock); - - return ret; -} - -int android_dlclose(void *handle) -{ - pthread_mutex_lock(&dl_lock); - (void)unload_library((soinfo*)handle); - pthread_mutex_unlock(&dl_lock); - return 0; -} - - -#if defined(ANDROID_ARM_LINKER) -// 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\0" - -_Unwind_Ptr android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount); - -#elif defined(ANDROID_X86_LINKER) -// 0000000 00011111 111112 22222222 2333333 3333444444444455 -// 0123456 78901234 567890 12345678 9012345 6789012345678901 -#define ANDROID_LIBDL_STRTAB \ - "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0" -int -android_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data), - void *data); - -#else -#error Unsupported architecture. Only ARM and x86 are presently supported. -#endif - - -static Elf32_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 - // in the strtab with a \0 to make iterating through the symtab easier. - { 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_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 7, - st_value: (Elf32_Addr) &android_dlclose, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 15, - st_value: (Elf32_Addr) &android_dlsym, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 21, - st_value: (Elf32_Addr) &android_dlerror, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 29, - st_value: (Elf32_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_info: STB_GLOBAL << 4, - st_shndx: 1, - }, -#elif defined(ANDROID_X86_LINKER) - { st_name: 36, - st_value: (Elf32_Addr) &android_dl_iterate_phdr, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, -#endif -}; - -/* Fake out a hash table with a single bucket. - * A search of the hash table will look through - * libdl_symtab starting with index [1], then - * use libdl_chains to find the next index to - * look at. libdl_chains should be set up to - * walk through every element in libdl_symtab, - * and then end with 0 (sentinel value). - * - * I.e., libdl_chains should look like - * { 0, 2, 3, ... N, 0 } where N is the number - * of actual symbols, or nelems(libdl_symtab)-1 - * (since the first element of libdl_symtab is not - * a real symbol). - * - * (see _elf_lookup()) - * - * Note that adding any new symbols here requires - * stubbing them out in libdl. - */ -static unsigned libdl_buckets[1] = { 1 }; -static unsigned libdl_chains[7] = { 0, 2, 3, 4, 5, 6, 0 }; - -soinfo libdl_info = { - name: "libdl.so", - flags: FLAG_LINKED, - - strtab: ANDROID_LIBDL_STRTAB, - symtab: libdl_symtab, - - nbucket: 1, - nchain: 7, - bucket: libdl_buckets, - chain: libdl_chains, -}; - diff --git a/hybris/common/gingerbread/linker.c b/hybris/common/gingerbread/linker.c deleted file mode 100644 index 5a9f8e764..000000000 --- a/hybris/common/gingerbread/linker.c +++ /dev/null @@ -1,2297 +0,0 @@ -/* - * Copyright (C) 2008, 2009 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 - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -/* special private C library header - see Android.mk */ -#include "bionic_tls.h" - -#include "linker.h" -#include "linker_debug.h" -#include "linker_environ.h" -#include "linker_format.h" - -#define ALLOW_SYMBOLS_FROM_MAIN 1 -#define SO_MAX 128 - -/* Assume average path length of 64 and max 8 paths */ -#define LDPATH_BUFSIZE 512 -#define LDPATH_MAX 8 - -#define LDPRELOAD_BUFSIZE 512 -#define LDPRELOAD_MAX 8 - -/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<< - * - * Do NOT use malloc() and friends or pthread_*() code here. - * Don't use printf() either; it's caused mysterious memory - * corruption in the past. - * The linker runs before we bring up libc and it's easiest - * to make sure it does not depend on any complex libc features - * - * open issues / todo: - * - * - are we doing everything we should for ARM_COPY relocations? - * - cleaner error reporting - * - after linking, set as much stuff as possible to READONLY - * and NOEXEC - * - linker hardcodes PAGE_SIZE and PAGE_MASK because the kernel - * headers provide versions that are negative... - * - allocate space for soinfo structs dynamically instead of - * having a hard limit (64) -*/ - - -static int link_image(soinfo *si, unsigned wr_offset); - -static int socount = 0; -static soinfo sopool[SO_MAX]; -static soinfo *freelist = NULL; -static soinfo *solist = &libdl_info; -static soinfo *sonext = &libdl_info; -#if ALLOW_SYMBOLS_FROM_MAIN -static soinfo *somain; /* main process, always the one after libdl_info */ -#endif - - -static inline int validate_soinfo(soinfo *si) -{ - return (si >= sopool && si < sopool + SO_MAX) || - si == &libdl_info; -} - -static char ldpaths_buf[LDPATH_BUFSIZE]; -static const char *ldpaths[LDPATH_MAX + 1]; - -static char ldpreloads_buf[LDPRELOAD_BUFSIZE]; -static const char *ldpreload_names[LDPRELOAD_MAX + 1]; - -static soinfo *preloads[LDPRELOAD_MAX + 1]; - -#if LINKER_DEBUG -int debug_verbosity; -#endif - -static int pid; - -/* This boolean is set if the program being loaded is setuid */ -static int program_is_setuid; - -#if STATS -struct _link_stats linker_stats; -#endif - -#if COUNT_PAGES -unsigned bitmask[4096]; -#endif - -#ifndef PT_ARM_EXIDX -#define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */ -#endif - -static char tmp_err_buf[768]; -static char __linker_dl_err_buf[768]; -#define DL_ERR(fmt, x...) \ - do { \ - format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf), \ - "%s[%d]: " fmt, __func__, __LINE__, ##x); \ - ERROR(fmt "\n", ##x); \ - } while(0) - -const char *linker_get_error(void) -{ - return (const char *)&__linker_dl_err_buf[0]; -} - -/* - * This function is an empty stub where GDB locates a breakpoint to get notified - * about linker activity. - */ -extern void __attribute__((noinline)) rtld_db_dlactivity(void); - -static struct r_debug _r_debug = {1, NULL, &rtld_db_dlactivity, - RT_CONSISTENT, 0}; -static struct link_map *r_debug_tail = 0; - -static pthread_mutex_t _r_debug_lock = PTHREAD_MUTEX_INITIALIZER; - -static void insert_soinfo_into_debug_map(soinfo * info) -{ - struct link_map * map; - - /* Copy the necessary fields into the debug structure. - */ - map = &(info->linkmap); - map->l_addr = info->base; - map->l_name = (char*) info->name; - map->l_ld = (uintptr_t)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) -{ - struct link_map * map = &(info->linkmap); - - 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; -} - -void notify_gdb_of_load(soinfo * info) -{ - if (info->flags & FLAG_EXE) { - // GDB already knows about the main executable - return; - } - - pthread_mutex_lock(&_r_debug_lock); - - _r_debug.r_state = RT_ADD; - rtld_db_dlactivity(); - - insert_soinfo_into_debug_map(info); - - _r_debug.r_state = RT_CONSISTENT; - rtld_db_dlactivity(); - - pthread_mutex_unlock(&_r_debug_lock); -} - -void notify_gdb_of_unload(soinfo * info) -{ - if (info->flags & FLAG_EXE) { - // GDB already knows about the main executable - return; - } - - pthread_mutex_lock(&_r_debug_lock); - - _r_debug.r_state = RT_DELETE; - rtld_db_dlactivity(); - - remove_soinfo_from_debug_map(info); - - _r_debug.r_state = RT_CONSISTENT; - rtld_db_dlactivity(); - - pthread_mutex_unlock(&_r_debug_lock); -} - -void notify_gdb_of_libraries() -{ - _r_debug.r_state = RT_ADD; - rtld_db_dlactivity(); - _r_debug.r_state = RT_CONSISTENT; - rtld_db_dlactivity(); -} - -static soinfo *alloc_info(const char *name) -{ - soinfo *si; - - if(strlen(name) >= SOINFO_NAME_LEN) { - DL_ERR("%5d library name %s too long", pid, name); - return NULL; - } - - /* The freelist is populated when we call free_info(), which in turn is - done only by dlclose(), which is not likely to be used. - */ - if (!freelist) { - if(socount == SO_MAX) { - DL_ERR("%5d too many libraries when loading %s", pid, name); - return NULL; - } - freelist = sopool + socount++; - freelist->next = NULL; - } - - si = freelist; - freelist = freelist->next; - - /* Make sure we get a clean block of soinfo */ - memset(si, 0, sizeof(soinfo)); - strlcpy((char*) si->name, name, sizeof(si->name)); - sonext->next = si; - si->next = NULL; - si->refcount = 0; - sonext = si; - - TRACE("%5d name %s: allocated soinfo @ %p\n", pid, name, si); - return si; -} - -static void free_info(soinfo *si) -{ - soinfo *prev = NULL, *trav; - - TRACE("%5d name %s: freeing soinfo @ %p\n", pid, si->name, si); - - for(trav = solist; trav != NULL; trav = trav->next){ - if (trav == si) - break; - prev = trav; - } - if (trav == NULL) { - /* si was not ni solist */ - DL_ERR("%5d name %s is not in solist!", pid, si->name); - return; - } - - /* 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->next = freelist; - freelist = si; -} - -const char *addr_to_name(unsigned addr) -{ - soinfo *si; - - for(si = solist; si != 0; si = si->next){ - if((addr >= si->base) && (addr < (si->base + si->size))) { - return si->name; - } - } - - return ""; -} - -/* 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.c and libdl.so. - */ -#ifdef ANDROID_ARM_LINKER -_Unwind_Ptr android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount) -{ - soinfo *si; - unsigned addr = (unsigned)pc; - - for (si = solist; si != 0; si = si->next){ - if ((addr >= si->base) && (addr < (si->base + si->size))) { - *pcount = si->ARM_exidx_count; - return (_Unwind_Ptr)(si->base + (unsigned long)si->ARM_exidx); - } - } - *pcount = 0; - return NULL; -} -#elif defined(ANDROID_X86_LINKER) -/* Here, we only have to provide a callback to iterate across all the - * loaded libraries. gcc_eh does the rest. */ -int -android_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data), - void *data) -{ - soinfo *si; - struct dl_phdr_info dl_info; - int rv = 0; - - for (si = solist; si != NULL; si = si->next) { - dl_info.dlpi_addr = si->linkmap.l_addr; - dl_info.dlpi_name = si->linkmap.l_name; - dl_info.dlpi_phdr = si->phdr; - dl_info.dlpi_phnum = si->phnum; - rv = cb(&dl_info, sizeof (struct dl_phdr_info), data); - if (rv != 0) - break; - } - return rv; -} -#endif - -static Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name) -{ - Elf32_Sym *s; - Elf32_Sym *symtab = si->symtab; - const char *strtab = si->strtab; - unsigned n; - - TRACE_TYPE(LOOKUP, "%5d SEARCH %s in %s@0x%08x %08x %d\n", pid, - name, si->name, si->base, hash, hash % si->nbucket); - if (si->nbucket == 0) { - return NULL; - } - n = hash % si->nbucket; - - for(n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]){ - s = symtab + n; - if(strcmp(strtab + s->st_name, name)) continue; - - /* only concern ourselves with global and weak symbol definitions */ - switch(ELF32_ST_BIND(s->st_info)){ - case STB_GLOBAL: - case STB_WEAK: - /* no section == undefined */ - if(s->st_shndx == 0) continue; - - TRACE_TYPE(LOOKUP, "%5d FOUND %s in %s (%08x) %d\n", pid, - name, si->name, s->st_value, s->st_size); - return s; - } - } - - return NULL; -} - -static unsigned elfhash(const char *_name) -{ - const unsigned char *name = (const unsigned char *) _name; - unsigned h = 0, g; - - while(*name) { - h = (h << 4) + *name++; - g = h & 0xf0000000; - h ^= g; - h ^= g >> 24; - } - return h; -} - -static Elf32_Sym * -_do_lookup(soinfo *si, const char *name, unsigned *base) -{ - unsigned elf_hash = elfhash(name); - Elf32_Sym *s; - unsigned *d; - soinfo *lsi = si; - int i; - - /* Look for symbols in the local scope (the object who is - * searching). This happens with C++ templates on i386 for some - * reason. - * - * Notes on weak symbols: - * The ELF specs are ambigious about treatment of weak definitions in - * dynamic linking. Some systems return the first definition found - * and some the first non-weak definition. This is system dependent. - * Here we return the first definition found for simplicity. */ - - s = _elf_lookup(si, elf_hash, name); - if(s != NULL) - goto done; - - /* Next, look for it in the preloads list */ - for(i = 0; preloads[i] != NULL; i++) { - lsi = preloads[i]; - s = _elf_lookup(lsi, elf_hash, name); - if(s != NULL) - goto done; - } - - for(d = si->dynamic; *d; d += 2) { - if(d[0] == DT_NEEDED){ - lsi = (soinfo *)d[1]; - if (!validate_soinfo(lsi)) { - DL_ERR("%5d bad DT_NEEDED pointer in %s", - pid, si->name); - return NULL; - } - - DEBUG("%5d %s: looking up %s in %s\n", - pid, si->name, name, lsi->name); - s = _elf_lookup(lsi, elf_hash, name); - if ((s != NULL) && (s->st_shndx != SHN_UNDEF)) - goto done; - } - } - -#if ALLOW_SYMBOLS_FROM_MAIN - /* If we are resolving relocations while dlopen()ing a library, it's OK for - * the library to resolve a symbol that's defined in the executable itself, - * although this is rare and is generally a bad idea. - */ - if (somain) { - lsi = somain; - DEBUG("%5d %s: looking up %s in executable %s\n", - pid, si->name, name, lsi->name); - s = _elf_lookup(lsi, elf_hash, name); - } -#endif - -done: - if(s != NULL) { - TRACE_TYPE(LOOKUP, "%5d si %s sym %s s->st_value = 0x%08x, " - "found in %s, base = 0x%08x\n", - pid, si->name, name, s->st_value, lsi->name, lsi->base); - *base = lsi->base; - return s; - } - - return NULL; -} - -/* 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) -{ - 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) -{ - unsigned elf_hash = elfhash(name); - Elf32_Sym *s = NULL; - soinfo *si; - - if(start == NULL) { - start = solist; - } - - for(si = start; (s == NULL) && (si != NULL); si = si->next) - { - if(si->flags & FLAG_ERROR) - continue; - s = _elf_lookup(si, elf_hash, name); - if (s != NULL) { - *found = si; - break; - } - } - - if(s != NULL) { - TRACE_TYPE(LOOKUP, "%5d %s s->st_value = 0x%08x, " - "si->base = 0x%08x\n", pid, name, s->st_value, si->base); - return s; - } - - return NULL; -} - -soinfo *find_containing_library(const void *addr) -{ - soinfo *si; - - for(si = solist; si != NULL; si = si->next) - { - if((unsigned)addr >= si->base && (unsigned)addr - si->base < si->size) { - return si; - } - } - - return NULL; -} - -Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si) -{ - unsigned int i; - unsigned soaddr = (unsigned)addr - si->base; - - /* Search the library's symbol table for any defined symbol which - * contains this address */ - for(i=0; inchain; i++) { - Elf32_Sym *sym = &si->symtab[i]; - - if(sym->st_shndx != SHN_UNDEF && - soaddr >= sym->st_value && - soaddr < sym->st_value + sym->st_size) { - return sym; - } - } - - return NULL; -} - -#if 0 -static void dump(soinfo *si) -{ - Elf32_Sym *s = si->symtab; - unsigned n; - - for(n = 0; n < si->nchain; n++) { - TRACE("%5d %04d> %08x: %02x %04x %08x %08x %s\n", pid, n, s, - s->st_info, s->st_shndx, s->st_value, s->st_size, - si->strtab + s->st_name); - s++; - } -} -#endif - -static const char *sopaths[] = { - "/vendor/lib", - "/system/lib", - 0 -}; - -static int _open_lib(const char *name) -{ - int fd; - struct stat filestat; - - if ((stat(name, &filestat) >= 0) && S_ISREG(filestat.st_mode)) { - if ((fd = open(name, O_RDONLY)) >= 0) - return fd; - } - - return -1; -} - -static int open_library(const char *name) -{ - int fd; - char buf[512]; - const char **path; - int n; - - TRACE("[ %5d opening %s ]\n", pid, name); - - if(name == 0) return -1; - if(strlen(name) > 256) return -1; - - if ((name[0] == '/') && ((fd = _open_lib(name)) >= 0)) - return fd; - - for (path = ldpaths; *path; path++) { - n = format_buffer(buf, sizeof(buf), "%s/%s", *path, name); - if (n < 0 || n >= (int)sizeof(buf)) { - WARN("Ignoring very long library path: %s/%s\n", *path, name); - continue; - } - if ((fd = _open_lib(buf)) >= 0) - return fd; - } - for (path = sopaths; *path; path++) { - n = format_buffer(buf, sizeof(buf), "%s/%s", *path, name); - if (n < 0 || n >= (int)sizeof(buf)) { - WARN("Ignoring very long library path: %s/%s\n", *path, name); - continue; - } - if ((fd = _open_lib(buf)) >= 0) - return fd; - } - - return -1; -} - -/* temporary space for holding the first page of the shared lib - * which contains the elf header (with the pht). */ -static unsigned char __header[PAGE_SIZE]; - -typedef struct { - long mmap_addr; - char tag[4]; /* 'P', 'R', 'E', ' ' */ -} prelink_info_t; - -/* Returns the requested base address if the library is prelinked, - * and 0 otherwise. */ -static unsigned long -is_prelinked(int fd, const char *name) -{ - off_t sz; - prelink_info_t info; - - sz = lseek(fd, -sizeof(prelink_info_t), SEEK_END); - if (sz < 0) { - DL_ERR("lseek() failed!"); - return 0; - } - - if (read(fd, &info, sizeof(info)) != sizeof(info)) { - WARN("Could not read prelink_info_t structure for `%s`\n", name); - return 0; - } - - if (strncmp(info.tag, "PRE ", 4)) { - WARN("`%s` is not a prelinked library\n", name); - return 0; - } - - return (unsigned long)info.mmap_addr; -} - -/* verify_elf_object - * Verifies if the object @ base is a valid ELF object - * - * Args: - * - * Returns: - * 0 on success - * -1 if no valid ELF object is found @ base. - */ -static int -verify_elf_object(void *base, const char *name) -{ - Elf32_Ehdr *hdr = (Elf32_Ehdr *) base; - - if (hdr->e_ident[EI_MAG0] != ELFMAG0) return -1; - if (hdr->e_ident[EI_MAG1] != ELFMAG1) return -1; - if (hdr->e_ident[EI_MAG2] != ELFMAG2) return -1; - if (hdr->e_ident[EI_MAG3] != ELFMAG3) return -1; - - /* TODO: Should we verify anything else in the header? */ -#ifdef ANDROID_ARM_LINKER - if (hdr->e_machine != EM_ARM) return -1; -#elif defined(ANDROID_X86_LINKER) - if (hdr->e_machine != EM_386) return -1; -#endif - return 0; -} - - -/* get_lib_extents - * Retrieves the base (*base) address where the ELF object should be - * mapped and its overall memory size (*total_sz). - * - * Args: - * fd: Opened file descriptor for the library - * name: The name of the library - * _hdr: Pointer to the header page of the library - * total_sz: Total size of the memory that should be allocated for - * this library - * - * Returns: - * -1 if there was an error while trying to get the lib extents. - * The possible reasons are: - * - Could not determine if the library was prelinked. - * - The library provided is not a valid ELF object - * 0 if the library did not request a specific base offset (normal - * for non-prelinked libs) - * > 0 if the library requests a specific address to be mapped to. - * This indicates a pre-linked library. - */ -static unsigned -get_lib_extents(int fd, const char *name, void *__hdr, unsigned *total_sz) -{ - unsigned req_base; - unsigned min_vaddr = 0xffffffff; - unsigned max_vaddr = 0; - unsigned char *_hdr = (unsigned char *)__hdr; - Elf32_Ehdr *ehdr = (Elf32_Ehdr *)_hdr; - Elf32_Phdr *phdr; - int cnt; - - TRACE("[ %5d Computing extents for '%s'. ]\n", pid, name); - if (verify_elf_object(_hdr, name) < 0) { - DL_ERR("%5d - %s is not a valid ELF object", pid, name); - return (unsigned)-1; - } - - req_base = (unsigned) is_prelinked(fd, name); - if (req_base == (unsigned)-1) - return -1; - else if (req_base != 0) { - TRACE("[ %5d - Prelinked library '%s' requesting base @ 0x%08x ]\n", - pid, name, req_base); - } else { - TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name); - } - - phdr = (Elf32_Phdr *)(_hdr + ehdr->e_phoff); - - /* find the min/max p_vaddrs from all the PT_LOAD segments so we can - * get the range. */ - for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) { - if (phdr->p_type == PT_LOAD) { - if ((phdr->p_vaddr + phdr->p_memsz) > max_vaddr) - max_vaddr = phdr->p_vaddr + phdr->p_memsz; - if (phdr->p_vaddr < min_vaddr) - min_vaddr = phdr->p_vaddr; - } - } - - if ((min_vaddr == 0xffffffff) && (max_vaddr == 0)) { - DL_ERR("%5d - No loadable segments found in %s.", pid, name); - return (unsigned)-1; - } - - /* truncate min_vaddr down to page boundary */ - min_vaddr &= ~PAGE_MASK; - - /* round max_vaddr up to the next page */ - max_vaddr = (max_vaddr + PAGE_SIZE - 1) & ~PAGE_MASK; - - *total_sz = (max_vaddr - min_vaddr); - return (unsigned)req_base; -} - -/* reserve_mem_region - * - * This function reserves a chunk of memory to be used for mapping in - * a prelinked shared library. We reserve the entire memory region here, and - * then the rest of the linker will relocate the individual loadable - * segments into the correct locations within this memory range. - * - * Args: - * si->base: The requested base of the allocation. - * si->size: The size of the allocation. - * - * Returns: - * -1 on failure, and 0 on success. On success, si->base will contain - * the virtual address at which the library will be mapped. - */ - -static int reserve_mem_region(soinfo *si) -{ - void *base = mmap((void *)si->base, si->size, PROT_NONE, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (base == MAP_FAILED) { - DL_ERR("%5d can NOT map (%sprelinked) library '%s' at 0x%08x " - "as requested, will try general pool: %d (%s)", - pid, (si->base ? "" : "non-"), si->name, si->base, - errno, strerror(errno)); - return -1; - } else if (base != (void *)si->base) { - DL_ERR("OOPS: %5d %sprelinked library '%s' mapped at 0x%08x, " - "not at 0x%08x", pid, (si->base ? "" : "non-"), - si->name, (unsigned)base, si->base); - munmap(base, si->size); - return -1; - } - return 0; -} - -static int alloc_mem_region(soinfo *si) -{ - if (si->base) { - /* Attempt to mmap a prelinked library. */ - return reserve_mem_region(si); - } - - /* This is not a prelinked library, so we use the kernel's default - allocator. - */ - - void *base = mmap(NULL, si->size, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (base == MAP_FAILED) { - DL_ERR("%5d mmap of library '%s' failed: %d (%s)\n", - pid, si->name, - errno, strerror(errno)); - goto err; - } - si->base = (unsigned) base; - PRINT("%5d mapped library '%s' to %08x via kernel allocator.\n", - pid, si->name, si->base); - return 0; - -err: - DL_ERR("OOPS: %5d cannot map library '%s'. no vspace available.", - pid, si->name); - return -1; -} - -#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)) -/* load_segments - * - * This function loads all the loadable (PT_LOAD) segments into memory - * at their appropriate memory offsets off the base address. - * - * Args: - * fd: Open file descriptor to the library to load. - * header: Pointer to a header page that contains the ELF header. - * This is needed since we haven't mapped in the real file yet. - * si: ptr to soinfo struct describing the shared object. - * - * Returns: - * 0 on success, -1 on failure. - */ -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; - int cnt; - unsigned len; - Elf32_Addr tmp; - unsigned char *pbase; - unsigned char *extra_base; - unsigned extra_len; - unsigned total_sz = 0; - - si->wrprotect_start = 0xffffffff; - si->wrprotect_end = 0; - - TRACE("[ %5d - Begin loading segments for '%s' @ 0x%08x ]\n", - pid, si->name, (unsigned)si->base); - /* Now go through all the PT_LOAD segments and map them into memory - * at the appropriate locations. */ - for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) { - if (phdr->p_type == PT_LOAD) { - DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid); - /* we want to map in the segment on a page boundary */ - tmp = base + (phdr->p_vaddr & (~PAGE_MASK)); - /* add the # of bytes we masked off above to the total length. */ - len = phdr->p_filesz + (phdr->p_vaddr & PAGE_MASK); - - TRACE("[ %d - Trying to load segment from '%s' @ 0x%08x " - "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x ]\n", pid, si->name, - (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset); - pbase = mmap((void *)tmp, len, PFLAGS_TO_PROT(phdr->p_flags), - MAP_PRIVATE | MAP_FIXED, fd, - phdr->p_offset & (~PAGE_MASK)); - if (pbase == MAP_FAILED) { - DL_ERR("%d failed to map segment from '%s' @ 0x%08x (0x%08x). " - "p_vaddr=0x%08x p_offset=0x%08x", pid, si->name, - (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset); - goto fail; - } - - /* If 'len' didn't end on page boundary, and it's a writable - * segment, zero-fill the rest. */ - if ((len & PAGE_MASK) && (phdr->p_flags & PF_W)) - memset((void *)(pbase + len), 0, PAGE_SIZE - (len & PAGE_MASK)); - - /* Check to see if we need to extend the map for this segment to - * cover the diff between filesz and memsz (i.e. for bss). - * - * base _+---------------------+ page boundary - * . . - * | | - * . . - * pbase _+---------------------+ page boundary - * | | - * . . - * base + p_vaddr _| | - * . \ \ . - * . | filesz | . - * pbase + len _| / | | - * <0 pad> . . . - * extra_base _+------------|--------+ page boundary - * / . . . - * | . . . - * | +------------|--------+ page boundary - * extra_len-> | | | | - * | . | memsz . - * | . | . - * \ _| / | - * . . - * | | - * _+---------------------+ page boundary - */ - tmp = (Elf32_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; - TRACE("[ %5d - Need to extend segment from '%s' @ 0x%08x " - "(0x%08x) ]\n", pid, si->name, (unsigned)tmp, extra_len); - /* map in the extra page(s) as anonymous into the range. - * This is probably not necessary as we already mapped in - * the entire region previously, but we just want to be - * sure. This will also set the right flags on the region - * (though we can probably accomplish the same thing with - * mprotect). - */ - extra_base = mmap((void *)tmp, extra_len, - PFLAGS_TO_PROT(phdr->p_flags), - MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, - -1, 0); - if (extra_base == MAP_FAILED) { - DL_ERR("[ %5d - failed to extend segment from '%s' @ 0x%08x" - " (0x%08x) ]", pid, si->name, (unsigned)tmp, - extra_len); - goto fail; - } - /* TODO: Check if we need to memset-0 this region. - * Anonymous mappings are zero-filled copy-on-writes, so we - * shouldn't need to. */ - TRACE("[ %5d - Segment from '%s' extended @ 0x%08x " - "(0x%08x)\n", pid, si->name, (unsigned)extra_base, - extra_len); - } - /* set the len here to show the full extent of the segment we - * just loaded, mostly for debugging */ - len = (((unsigned)base + phdr->p_vaddr + phdr->p_memsz + - PAGE_SIZE - 1) & (~PAGE_MASK)) - (unsigned)pbase; - TRACE("[ %5d - Successfully loaded segment from '%s' @ 0x%08x " - "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x\n", pid, si->name, - (unsigned)pbase, len, phdr->p_vaddr, phdr->p_offset); - total_sz += len; - /* Make the section writable just in case we'll have to write to - * it during relocation (i.e. text segment). However, we will - * remember what range of addresses should be write protected. - * - */ - if (!(phdr->p_flags & PF_W)) { - if ((unsigned)pbase < si->wrprotect_start) - si->wrprotect_start = (unsigned)pbase; - if (((unsigned)pbase + len) > si->wrprotect_end) - si->wrprotect_end = (unsigned)pbase + len; - mprotect(pbase, len, - PFLAGS_TO_PROT(phdr->p_flags) | PROT_WRITE); - } - } else if (phdr->p_type == PT_DYNAMIC) { - DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid); - /* this segment contains the dynamic linking information */ - si->dynamic = (unsigned *)(base + phdr->p_vaddr); - } else if (phdr->p_type == PT_GNU_RELRO) { - if ((phdr->p_vaddr >= si->size) - || ((phdr->p_vaddr + phdr->p_memsz) > si->size) - || ((base + phdr->p_vaddr + phdr->p_memsz) < base)) { - DL_ERR("%d invalid GNU_RELRO in '%s' " - "p_vaddr=0x%08x p_memsz=0x%08x", pid, si->name, - phdr->p_vaddr, phdr->p_memsz); - goto fail; - } - si->gnu_relro_start = (Elf32_Addr) (base + phdr->p_vaddr); - si->gnu_relro_len = (unsigned) phdr->p_memsz; - } else { -#ifdef ANDROID_ARM_LINKER - if (phdr->p_type == PT_ARM_EXIDX) { - DEBUG_DUMP_PHDR(phdr, "PT_ARM_EXIDX", pid); - /* exidx entries (used for stack unwinding) are 8 bytes each. - */ - si->ARM_exidx = (unsigned *)phdr->p_vaddr; - si->ARM_exidx_count = phdr->p_memsz / 8; - } -#endif - } - - } - - /* Sanity check */ - if (total_sz > si->size) { - DL_ERR("%5d - Total length (0x%08x) of mapped segments from '%s' is " - "greater than what was allocated (0x%08x). THIS IS BAD!", - pid, total_sz, si->name, si->size); - goto fail; - } - - TRACE("[ %5d - Finish loading segments for '%s' @ 0x%08x. " - "Total memory footprint: 0x%08x bytes ]\n", pid, si->name, - (unsigned)si->base, si->size); - return 0; - -fail: - /* We can just blindly unmap the entire region even though some things - * were mapped in originally with anonymous and others could have been - * been mapped in from the file before we failed. The kernel will unmap - * all the pages in the range, irrespective of how they got there. - */ - munmap((void *)si->base, si->size); - si->flags |= FLAG_ERROR; - return -1; -} - -/* TODO: Implement this to take care of the fact that Android ARM - * ELF objects shove everything into a single loadable segment that has the - * write bit set. wr_offset is then used to set non-(data|bss) pages to be - * non-writable. - */ -#if 0 -static unsigned -get_wr_offset(int fd, const char *name, Elf32_Ehdr *ehdr) -{ - Elf32_Shdr *shdr_start; - Elf32_Shdr *shdr; - int shdr_sz = ehdr->e_shnum * sizeof(Elf32_Shdr); - int cnt; - unsigned wr_offset = 0xffffffff; - - shdr_start = mmap(0, shdr_sz, PROT_READ, MAP_PRIVATE, fd, - ehdr->e_shoff & (~PAGE_MASK)); - if (shdr_start == MAP_FAILED) { - WARN("%5d - Could not read section header info from '%s'. Will not " - "not be able to determine write-protect offset.\n", pid, name); - return (unsigned)-1; - } - - for(cnt = 0, shdr = shdr_start; cnt < ehdr->e_shnum; ++cnt, ++shdr) { - if ((shdr->sh_type != SHT_NULL) && (shdr->sh_flags & SHF_WRITE) && - (shdr->sh_addr < wr_offset)) { - wr_offset = shdr->sh_addr; - } - } - - munmap(shdr_start, shdr_sz); - return wr_offset; -} -#endif - -static soinfo * -load_library(const char *name) -{ - int fd = open_library(name); - int cnt; - unsigned ext_sz; - unsigned req_base; - const char *bname; - soinfo *si = NULL; - Elf32_Ehdr *hdr; - - if(fd == -1) { - DL_ERR("Library '%s' not found", name); - return NULL; - } - - /* We have to read the ELF header to figure out what to do with this image - */ - if (lseek(fd, 0, SEEK_SET) < 0) { - DL_ERR("lseek() failed!"); - goto fail; - } - - if ((cnt = read(fd, &__header[0], PAGE_SIZE)) < 0) { - DL_ERR("read() failed!"); - goto fail; - } - - /* Parse the ELF header and get the size of the memory footprint for - * the library */ - req_base = get_lib_extents(fd, name, &__header[0], &ext_sz); - if (req_base == (unsigned)-1) - goto fail; - TRACE("[ %5d - '%s' (%s) wants base=0x%08x sz=0x%08x ]\n", pid, name, - (req_base ? "prelinked" : "not pre-linked"), req_base, ext_sz); - - /* Now configure the soinfo struct where we'll store all of our data - * for the ELF object. If the loading fails, we waste the entry, but - * same thing would happen if we failed during linking. Configuring the - * soinfo struct here is a lot more convenient. - */ - bname = strrchr(name, '/'); - si = alloc_info(bname ? bname + 1 : name); - if (si == NULL) - goto fail; - - /* Carve out a chunk of memory where we will map in the individual - * segments */ - si->base = req_base; - si->size = ext_sz; - si->flags = 0; - si->entry = 0; - si->dynamic = (unsigned *)-1; - if (alloc_mem_region(si) < 0) - goto fail; - - TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n", - pid, name, (void *)si->base, (unsigned) ext_sz); - - /* Now actually load the library's segments into right places in memory */ - if (load_segments(fd, &__header[0], si) < 0) { - goto fail; - } - - /* 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); - si->phnum = hdr->e_phnum; - /**/ - - close(fd); - return si; - -fail: - if (si) free_info(si); - close(fd); - return NULL; -} - -static soinfo * -init_library(soinfo *si) -{ - unsigned wr_offset = 0xffffffff; - - /* At this point we know that whatever is loaded @ base is a valid ELF - * shared library whose segments are properly mapped in. */ - TRACE("[ %5d init_library base=0x%08x sz=0x%08x name='%s') ]\n", - pid, si->base, si->size, si->name); - - if(link_image(si, wr_offset)) { - /* We failed to link. However, we can only restore libbase - ** if no additional libraries have moved it since we updated it. - */ - munmap((void *)si->base, si->size); - return NULL; - } - - return si; -} - -soinfo *find_library(const char *name) -{ - soinfo *si; - const char *bname; - -#if ALLOW_SYMBOLS_FROM_MAIN - if (name == NULL) - return somain; -#else - if (name == NULL) - return NULL; -#endif - - bname = strrchr(name, '/'); - bname = bname ? bname + 1 : name; - - for(si = solist; si != 0; si = si->next){ - if(!strcmp(bname, si->name)) { - if(si->flags & FLAG_ERROR) { - DL_ERR("%5d '%s' failed to load previously", pid, bname); - return NULL; - } - if(si->flags & FLAG_LINKED) return si; - DL_ERR("OOPS: %5d recursive link to '%s'", pid, si->name); - return NULL; - } - } - - TRACE("[ %5d '%s' has not been loaded yet. Locating...]\n", pid, name); - si = load_library(name); - if(si == NULL) - return NULL; - return init_library(si); -} - -/* TODO: - * notify gdb of unload - * for non-prelinked libraries, find a way to decrement libbase - */ -static void call_destructors(soinfo *si); -unsigned unload_library(soinfo *si) -{ - unsigned *d; - if (si->refcount == 1) { - TRACE("%5d unloading '%s'\n", pid, si->name); - call_destructors(si); - - /* - * Make sure that we undo the PT_GNU_RELRO protections we added - * 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); - 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. " - "Expect a crash soon. errno=%d (%s)", - pid, si->name, errno, strerror(errno)); - - } - - for(d = si->dynamic; *d; d += 2) { - if(d[0] == DT_NEEDED){ - soinfo *lsi = (soinfo *)d[1]; - - // The next line will segfault if the we don't undo the - // PT_GNU_RELRO protections (see comments above and in - // link_image(). - d[1] = 0; - - if (validate_soinfo(lsi)) { - TRACE("%5d %s needs to unload %s\n", pid, - si->name, lsi->name); - unload_library(lsi); - } - else - DL_ERR("%5d %s: could not unload dependent library", - pid, si->name); - } - } - - munmap((char *)si->base, si->size); - notify_gdb_of_unload(si); - free_info(si); - si->refcount = 0; - } - else { - si->refcount--; - PRINT("%5d not unloading '%s', decrementing refcount to %d\n", - pid, si->name, si->refcount); - } - return si->refcount; -} - -/* 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 - * long. - */ -static int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count) -{ - Elf32_Sym *symtab = si->symtab; - const char *strtab = si->strtab; - Elf32_Sym *s; - unsigned base; - Elf32_Rel *start = rel; - unsigned idx; - - for (idx = 0; idx < count; ++idx) { - unsigned type = ELF32_R_TYPE(rel->r_info); - unsigned sym = ELF32_R_SYM(rel->r_info); - unsigned reloc = (unsigned)(rel->r_offset + si->base); - unsigned sym_addr = 0; - char *sym_name = NULL; - - DEBUG("%5d Processing '%s' relocation at index %d\n", pid, - si->name, idx); - if(sym != 0) { - sym_name = (char *)(strtab + symtab[sym].st_name); - sym_addr = NULL; - if ((sym_addr = get_hooked_symbol(sym_name)) != NULL) { - DEBUG("hooked symbol %s to %x\n", sym_name, sym_addr); - } - else - { - s = _do_lookup(si, sym_name, &base); - } - if(sym_addr != NULL) - { - } else - if(s == NULL) { - /* We only allow an undefined symbol if this is a weak - reference.. */ - s = &symtab[sym]; - if (ELF32_ST_BIND(s->st_info) != STB_WEAK) { - DL_ERR("%5d cannot locate '%s'...\n", pid, sym_name); - return -1; - } - - /* 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 nominial base address if the relocation - type is base-relative. - */ - - switch (type) { -#if defined(ANDROID_ARM_LINKER) - case R_ARM_JUMP_SLOT: - case R_ARM_GLOB_DAT: - case R_ARM_ABS32: - case R_ARM_RELATIVE: /* Don't care. */ - case R_ARM_NONE: /* Don't care. */ -#elif defined(ANDROID_X86_LINKER) - case R_386_JUMP_SLOT: - case R_386_GLOB_DAT: - case R_386_32: - case R_386_RELATIVE: /* Dont' care. */ -#endif /* ANDROID_*_LINKER */ - /* sym_addr was initialized to be zero above or relocation - code below does not care about value of sym_addr. - No need to do anything. */ - break; - -#if defined(ANDROID_X86_LINKER) - case R_386_PC32: - sym_addr = reloc; - break; -#endif /* ANDROID_X86_LINKER */ - -#if defined(ANDROID_ARM_LINKER) - case R_ARM_COPY: - /* Fall through. Can't really copy if weak symbol is - not found in run-time. */ -#endif /* ANDROID_ARM_LINKER */ - default: - DL_ERR("%5d unknown weak reloc type %d @ %p (%d)\n", - pid, type, rel, (int) (rel - start)); - return -1; - } - } else { - /* We got a definition. */ -#if 0 - if((base == 0) && (si->base != 0)){ - /* linking from libraries to main image is bad */ - DL_ERR("%5d cannot locate '%s'...", - pid, strtab + symtab[sym].st_name); - return -1; - } -#endif - sym_addr = (unsigned)(s->st_value + base); - } - COUNT_RELOC(RELOC_SYMBOL); - } else { - s = NULL; - } - -/* TODO: This is ugly. Split up the relocations by arch into - * different files. - */ - switch(type){ -#if defined(ANDROID_ARM_LINKER) - case R_ARM_JUMP_SLOT: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) = sym_addr; - break; - case R_ARM_GLOB_DAT: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) = sym_addr; - break; - case R_ARM_ABS32: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO ABS %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) += sym_addr; - break; - case R_ARM_REL32: - COUNT_RELOC(RELOC_RELATIVE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO REL32 %08x <- %08x - %08x %s\n", pid, - reloc, sym_addr, rel->r_offset, sym_name); - *((unsigned*)reloc) += sym_addr - rel->r_offset; - break; -#elif defined(ANDROID_X86_LINKER) - case R_386_JUMP_SLOT: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) = sym_addr; - break; - case R_386_GLOB_DAT: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) = sym_addr; - break; -#endif /* ANDROID_*_LINKER */ - -#if defined(ANDROID_ARM_LINKER) - case R_ARM_RELATIVE: -#elif defined(ANDROID_X86_LINKER) - case R_386_RELATIVE: -#endif /* ANDROID_*_LINKER */ - COUNT_RELOC(RELOC_RELATIVE); - MARK(rel->r_offset); - if(sym){ - DL_ERR("%5d odd RELATIVE form...", pid); - return -1; - } - TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid, - reloc, si->base); - *((unsigned*)reloc) += si->base; - break; - -#if defined(ANDROID_X86_LINKER) - case R_386_32: - COUNT_RELOC(RELOC_RELATIVE); - MARK(rel->r_offset); - - TRACE_TYPE(RELO, "%5d RELO R_386_32 %08x <- +%08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned *)reloc) += (unsigned)sym_addr; - break; - - case R_386_PC32: - COUNT_RELOC(RELOC_RELATIVE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO R_386_PC32 %08x <- " - "+%08x (%08x - %08x) %s\n", pid, reloc, - (sym_addr - reloc), sym_addr, reloc, sym_name); - *((unsigned *)reloc) += (unsigned)(sym_addr - reloc); - break; -#endif /* ANDROID_X86_LINKER */ - -#ifdef ANDROID_ARM_LINKER - case R_ARM_COPY: - COUNT_RELOC(RELOC_COPY); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO %08x <- %d @ %08x %s\n", pid, - reloc, s->st_size, sym_addr, sym_name); - memcpy((void*)reloc, (void*)sym_addr, s->st_size); - break; - case R_ARM_NONE: - break; -#endif /* ANDROID_ARM_LINKER */ - - default: - DL_ERR("%5d unknown reloc type %d @ %p (%d)", - pid, type, rel, (int) (rel - start)); - return -1; - } - rel++; - } - return 0; -} - -/* Please read the "Initialization and Termination functions" functions. - * of the linker design note in bionic/linker/README.TXT to understand - * what the following code is doing. - * - * The important things to remember are: - * - * DT_PREINIT_ARRAY must be called first for executables, and should - * not appear in shared libraries. - * - * DT_INIT should be called before DT_INIT_ARRAY if both are present - * - * DT_FINI should be called after DT_FINI_ARRAY if both are present - * - * DT_FINI_ARRAY must be parsed in reverse order. - */ - -static void call_array(unsigned *ctor, int count, int reverse) -{ - int n, inc = 1; - - if (reverse) { - ctor += (count-1); - inc = -1; - } - - for(n = count; n > 0; n--) { - TRACE("[ %5d Looking at %s *0x%08x == 0x%08x ]\n", pid, - reverse ? "dtor" : "ctor", - (unsigned)ctor, (unsigned)*ctor); - void (*func)() = (void (*)()) *ctor; - ctor += inc; - if(((int) func == 0) || ((int) func == -1)) continue; - TRACE("[ %5d Calling func @ 0x%08x ]\n", pid, (unsigned)func); - func(); - } -} - -void call_constructors_recursive(soinfo *si) -{ - if (si->constructors_called) - return; - if (strcmp(si->name, "libc.so") == 0) - return; - // Set this 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 call_constructors_recursive() with the newly created - // soinfo for libc_malloc_debug_leak.so. - // 4. The debug so depends on libc, so call_constructors_recursive() is - // called again with the libc soinfo. If it doesn't trigger the early- - // out above, the libc constructor will be called again (recursively!). - si->constructors_called = 1; - - if (si->flags & FLAG_EXE) { - TRACE("[ %5d Calling preinit_array @ 0x%08x [%d] for '%s' ]\n", - pid, (unsigned)si->preinit_array, si->preinit_array_count, - si->name); - call_array(si->preinit_array, si->preinit_array_count, 0); - TRACE("[ %5d Done calling preinit_array for '%s' ]\n", pid, si->name); - } else { - if (si->preinit_array) { - DL_ERR("%5d Shared library '%s' has a preinit_array table @ 0x%08x." - " This is INVALID.", pid, si->name, - (unsigned)si->preinit_array); - } - } - - if (si->dynamic) { - unsigned *d; - for(d = si->dynamic; *d; d += 2) { - if(d[0] == DT_NEEDED){ - soinfo* lsi = (soinfo *)d[1]; - if (!validate_soinfo(lsi)) { - DL_ERR("%5d bad DT_NEEDED pointer in %s", - pid, si->name); - } else { - call_constructors_recursive(lsi); - } - } - } - } - - if (si->init_func) { - TRACE("[ %5d Calling init_func @ 0x%08x for '%s' ]\n", pid, - (unsigned)si->init_func, si->name); - si->init_func(); - TRACE("[ %5d Done calling init_func for '%s' ]\n", pid, si->name); - } - - if (si->init_array) { - TRACE("[ %5d Calling init_array @ 0x%08x [%d] for '%s' ]\n", pid, - (unsigned)si->init_array, si->init_array_count, si->name); - call_array(si->init_array, si->init_array_count, 0); - TRACE("[ %5d Done calling init_array for '%s' ]\n", pid, si->name); - } - -} - -static void call_destructors(soinfo *si) -{ - if (si->fini_array) { - TRACE("[ %5d Calling fini_array @ 0x%08x [%d] for '%s' ]\n", pid, - (unsigned)si->fini_array, si->fini_array_count, si->name); - call_array(si->fini_array, si->fini_array_count, 1); - TRACE("[ %5d Done calling fini_array for '%s' ]\n", pid, si->name); - } - - if (si->fini_func) { - TRACE("[ %5d Calling fini_func @ 0x%08x for '%s' ]\n", pid, - (unsigned)si->fini_func, si->name); - si->fini_func(); - TRACE("[ %5d Done calling fini_func for '%s' ]\n", pid, si->name); - } -} - -/* Force any of the closed stdin, stdout and stderr to be associated with - /dev/null. */ -static int nullify_closed_stdio (void) -{ - int dev_null, i, status; - int return_value = 0; - - dev_null = open("/dev/null", O_RDWR); - if (dev_null < 0) { - DL_ERR("Cannot open /dev/null."); - return -1; - } - TRACE("[ %5d Opened /dev/null file-descriptor=%d]\n", pid, dev_null); - - /* If any of the stdio file descriptors is valid and not associated - with /dev/null, dup /dev/null to it. */ - for (i = 0; i < 3; i++) { - /* If it is /dev/null already, we are done. */ - if (i == dev_null) - continue; - - TRACE("[ %5d Nullifying stdio file descriptor %d]\n", pid, i); - /* The man page of fcntl does not say that fcntl(..,F_GETFL) - can be interrupted but we do this just to be safe. */ - do { - status = fcntl(i, F_GETFL); - } while (status < 0 && errno == EINTR); - - /* If file is openned, we are good. */ - if (status >= 0) - continue; - - /* The only error we allow is that the file descriptor does not - exist, in which case we dup /dev/null to it. */ - if (errno != EBADF) { - DL_ERR("nullify_stdio: unhandled error %s", strerror(errno)); - return_value = -1; - continue; - } - - /* Try dupping /dev/null to this stdio file descriptor and - repeat if there is a signal. Note that any errors in closing - the stdio descriptor are lost. */ - do { - status = dup2(dev_null, i); - } while (status < 0 && errno == EINTR); - - if (status < 0) { - DL_ERR("nullify_stdio: dup2 error %s", strerror(errno)); - return_value = -1; - continue; - } - } - - /* If /dev/null is not one of the stdio file descriptors, close it. */ - if (dev_null > 2) { - TRACE("[ %5d Closing /dev/null file-descriptor=%d]\n", pid, dev_null); - do { - status = close(dev_null); - } while (status < 0 && errno == EINTR); - - if (status < 0) { - DL_ERR("nullify_stdio: close error %s", strerror(errno)); - return_value = -1; - } - } - - return return_value; -} - -static int link_image(soinfo *si, unsigned wr_offset) -{ - unsigned *d; - Elf32_Phdr *phdr = si->phdr; - int phnum = si->phnum; - - INFO("[ %5d linking %s ]\n", pid, si->name); - DEBUG("%5d si->base = 0x%08x si->flags = 0x%08x\n", pid, - si->base, si->flags); - - if (si->flags & (FLAG_EXE | FLAG_LINKER)) { - /* Locate the needed program segments (DYNAMIC/ARM_EXIDX) for - * linkage info if this is the executable or the linker itself. - * If this was a dynamic lib, that would have been done at load time. - * - * TODO: It's unfortunate that small pieces of this are - * repeated from the load_library routine. Refactor this just - * slightly to reuse these bits. - */ - si->size = 0; - for(; phnum > 0; --phnum, ++phdr) { -#ifdef ANDROID_ARM_LINKER - if(phdr->p_type == PT_ARM_EXIDX) { - /* exidx entries (used for stack unwinding) are 8 bytes each. - */ - si->ARM_exidx = (unsigned *)phdr->p_vaddr; - si->ARM_exidx_count = phdr->p_memsz / 8; - } -#endif - if (phdr->p_type == PT_LOAD) { - /* For the executable, we use the si->size field only in - dl_unwind_find_exidx(), so the meaning of si->size - is not the size of the executable; it is the distance - between the load location of the executable and the last - address of the loadable part of the executable. - We use the range [si->base, si->base + si->size) to - determine whether a PC value falls within the executable - section. Of course, if a value is between si->base and - (si->base + phdr->p_vaddr), it's not in the executable - section, but a) we shouldn't be asking for such a value - anyway, and b) if we have to provide an EXIDX for such a - value, then the executable's EXIDX is probably the better - choice. - */ - DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid); - if (phdr->p_vaddr + phdr->p_memsz > si->size) - si->size = phdr->p_vaddr + phdr->p_memsz; - /* try to remember what range of addresses should be write - * protected */ - if (!(phdr->p_flags & PF_W)) { - unsigned _end; - - if (si->base + phdr->p_vaddr < si->wrprotect_start) - si->wrprotect_start = si->base + phdr->p_vaddr; - _end = (((si->base + phdr->p_vaddr + phdr->p_memsz + PAGE_SIZE - 1) & - (~PAGE_MASK))); - if (_end > si->wrprotect_end) - si->wrprotect_end = _end; - /* Make the section writable just in case we'll have to - * write to it during relocation (i.e. text segment). - * However, we will remember what range of addresses - * should be write protected. - */ - mprotect((void *) (si->base + phdr->p_vaddr), - phdr->p_memsz, - PFLAGS_TO_PROT(phdr->p_flags) | PROT_WRITE); - } - } else if (phdr->p_type == PT_DYNAMIC) { - if (si->dynamic != (unsigned *)-1) { - DL_ERR("%5d multiple PT_DYNAMIC segments found in '%s'. " - "Segment at 0x%08x, previously one found at 0x%08x", - pid, si->name, si->base + phdr->p_vaddr, - (unsigned)si->dynamic); - goto fail; - } - DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid); - si->dynamic = (unsigned *) (si->base + phdr->p_vaddr); - } else if (phdr->p_type == PT_GNU_RELRO) { - if ((phdr->p_vaddr >= si->size) - || ((phdr->p_vaddr + phdr->p_memsz) > si->size) - || ((si->base + phdr->p_vaddr + phdr->p_memsz) < si->base)) { - DL_ERR("%d invalid GNU_RELRO in '%s' " - "p_vaddr=0x%08x p_memsz=0x%08x", pid, si->name, - phdr->p_vaddr, phdr->p_memsz); - goto fail; - } - si->gnu_relro_start = (Elf32_Addr) (si->base + phdr->p_vaddr); - si->gnu_relro_len = (unsigned) phdr->p_memsz; - } - } - } - - if (si->dynamic == (unsigned *)-1) { - DL_ERR("%5d missing PT_DYNAMIC?!", pid); - goto fail; - } - - DEBUG("%5d dynamic = %p\n", pid, si->dynamic); - - /* extract useful information from dynamic section */ - for(d = si->dynamic; *d; d++){ - DEBUG("%5d d = %p, d[0] = 0x%08x d[1] = 0x%08x\n", pid, d, d[0], d[1]); - switch(*d++){ - case DT_HASH: - si->nbucket = ((unsigned *) (si->base + *d))[0]; - si->nchain = ((unsigned *) (si->base + *d))[1]; - si->bucket = (unsigned *) (si->base + *d + 8); - si->chain = (unsigned *) (si->base + *d + 8 + si->nbucket * 4); - break; - case DT_STRTAB: - si->strtab = (const char *) (si->base + *d); - break; - case DT_SYMTAB: - si->symtab = (Elf32_Sym *) (si->base + *d); - break; - case DT_PLTREL: - if(*d != DT_REL) { - DL_ERR("DT_RELA not supported"); - goto fail; - } - break; - case DT_JMPREL: - si->plt_rel = (Elf32_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); - break; - case DT_RELSZ: - si->rel_count = *d / 8; - break; - case DT_PLTGOT: - /* Save this in case we decide to do lazy binding. We don't yet. */ - si->plt_got = (unsigned *)(si->base + *d); - break; - case DT_DEBUG: - // Set the DT_DEBUG entry to the addres of _r_debug for GDB - *d = (int) &_r_debug; - break; - case DT_RELA: - DL_ERR("%5d DT_RELA not supported", pid); - goto fail; - case DT_INIT: - si->init_func = (void (*)(void))(si->base + *d); - DEBUG("%5d %s constructors (init func) found at %p\n", - pid, si->name, si->init_func); - break; - case DT_FINI: - si->fini_func = (void (*)(void))(si->base + *d); - DEBUG("%5d %s destructors (fini func) found at %p\n", - pid, si->name, si->fini_func); - break; - case DT_INIT_ARRAY: - si->init_array = (unsigned *)(si->base + *d); - DEBUG("%5d %s constructors (init_array) found at %p\n", - pid, si->name, si->init_array); - break; - case DT_INIT_ARRAYSZ: - si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); - break; - case DT_FINI_ARRAY: - si->fini_array = (unsigned *)(si->base + *d); - DEBUG("%5d %s destructors (fini_array) found at %p\n", - pid, si->name, si->fini_array); - break; - case DT_FINI_ARRAYSZ: - si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); - break; - case DT_PREINIT_ARRAY: - si->preinit_array = (unsigned *)(si->base + *d); - DEBUG("%5d %s constructors (preinit_array) found at %p\n", - pid, si->name, si->preinit_array); - break; - case DT_PREINIT_ARRAYSZ: - si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); - break; - case DT_TEXTREL: - /* TODO: make use of this. */ - /* this means that we might have to write into where the text - * segment was loaded during relocation... Do something with - * it. - */ - DEBUG("%5d Text segment should be writable during relocation.\n", - pid); - break; - } - } - - DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n", - pid, si->base, si->strtab, si->symtab); - - if((si->strtab == 0) || (si->symtab == 0)) { - DL_ERR("%5d missing essential tables", pid); - goto fail; - } - - /* if this is the main executable, then load all of the preloads now */ - if(si->flags & FLAG_EXE) { - int i; - memset(preloads, 0, sizeof(preloads)); - for(i = 0; ldpreload_names[i] != NULL; i++) { - soinfo *lsi = find_library(ldpreload_names[i]); - if(lsi == 0) { - strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf)); - DL_ERR("%5d could not load needed library '%s' for '%s' (%s)", - pid, ldpreload_names[i], si->name, tmp_err_buf); - goto fail; - } - lsi->refcount++; - preloads[i] = lsi; - } - } - - for(d = si->dynamic; *d; d += 2) { - if(d[0] == DT_NEEDED){ - DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]); - soinfo *lsi = find_library(si->strtab + d[1]); - if(lsi == 0) { - strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf)); - DL_ERR("%5d could not load needed library '%s' for '%s' (%s)", - pid, si->strtab + d[1], si->name, tmp_err_buf); - goto fail; - } - /* Save the soinfo of the loaded DT_NEEDED library in the payload - of the DT_NEEDED entry itself, so that we can retrieve the - soinfo directly later from the dynamic segment. This is a hack, - but it allows us to map from DT_NEEDED to soinfo efficiently - later on when we resolve relocations, trying to look up a symbol - with dlsym(). - */ - d[1] = (unsigned)lsi; - lsi->refcount++; - } - } - - if(si->plt_rel) { - DEBUG("[ %5d relocating %s plt ]\n", pid, si->name ); - if(reloc_library(si, si->plt_rel, si->plt_rel_count)) - goto fail; - } - if(si->rel) { - DEBUG("[ %5d relocating %s ]\n", pid, si->name ); - if(reloc_library(si, si->rel, si->rel_count)) - goto fail; - } - - si->flags |= FLAG_LINKED; - DEBUG("[ %5d finished linking %s ]\n", pid, si->name); - -#if 0 - /* This is the way that the old dynamic linker did protection of - * non-writable areas. It would scan section headers and find where - * .text ended (rather where .data/.bss began) and assume that this is - * the upper range of the non-writable area. This is too coarse, - * and is kept here for reference until we fully move away from single - * segment elf objects. See the code in get_wr_offset (also #if'd 0) - * that made this possible. - */ - if(wr_offset < 0xffffffff){ - mprotect((void*) si->base, wr_offset, PROT_READ | PROT_EXEC); - } -#else - /* TODO: Verify that this does the right thing in all cases, as it - * presently probably does not. It is possible that an ELF image will - * come with multiple read-only segments. What we ought to do is scan - * the program headers again and mprotect all the read-only segments. - * To prevent re-scanning the program header, we would have to build a - * list of loadable segments in si, and then scan that instead. */ - if (si->wrprotect_start != 0xffffffff && si->wrprotect_end != 0) { - mprotect((void *)si->wrprotect_start, - si->wrprotect_end - si->wrprotect_start, - PROT_READ | PROT_EXEC); - } -#endif - - if (si->gnu_relro_start != 0 && si->gnu_relro_len != 0) { - Elf32_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", - pid, si->name, errno, strerror(errno)); - goto fail; - } - } - - /* If this is a SET?ID program, dup /dev/null to opened stdin, - stdout and stderr to close a security hole described in: - - ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc - - */ - if (program_is_setuid) - nullify_closed_stdio (); - notify_gdb_of_load(si); - return 0; - -fail: - ERROR("failed to link %s\n", si->name); - si->flags |= FLAG_ERROR; - return -1; -} - -static void parse_library_path(const char *path, char *delim) -{ - size_t len; - char *ldpaths_bufp = ldpaths_buf; - int i = 0; - - len = strlcpy(ldpaths_buf, path, sizeof(ldpaths_buf)); - - while (i < LDPATH_MAX && (ldpaths[i] = strsep(&ldpaths_bufp, delim))) { - if (*ldpaths[i] != '\0') - ++i; - } - - /* Forget the last path if we had to truncate; this occurs if the 2nd to - * last char isn't '\0' (i.e. not originally a delim). */ - if (i > 0 && len >= sizeof(ldpaths_buf) && - ldpaths_buf[sizeof(ldpaths_buf) - 2] != '\0') { - ldpaths[i - 1] = NULL; - } else { - ldpaths[i] = NULL; - } -} - -static void parse_preloads(const char *path, char *delim) -{ - size_t len; - char *ldpreloads_bufp = ldpreloads_buf; - int i = 0; - - len = strlcpy(ldpreloads_buf, path, sizeof(ldpreloads_buf)); - - while (i < LDPRELOAD_MAX && (ldpreload_names[i] = strsep(&ldpreloads_bufp, delim))) { - if (*ldpreload_names[i] != '\0') { - ++i; - } - } - - /* Forget the last path if we had to truncate; this occurs if the 2nd to - * last char isn't '\0' (i.e. not originally a delim). */ - if (i > 0 && len >= sizeof(ldpreloads_buf) && - ldpreloads_buf[sizeof(ldpreloads_buf) - 2] != '\0') { - ldpreload_names[i - 1] = NULL; - } else { - ldpreload_names[i] = NULL; - } -} - -/* - * 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 unsigned __linker_init_post_relocation(unsigned **elfdata) -{ - static soinfo linker_soinfo; - - int argc = (int) *elfdata; - char **argv = (char**) (elfdata + 1); - unsigned *vecs = (unsigned*) (argv + argc + 1); - unsigned *v; - soinfo *si; - struct link_map * map; - const char *ldpath_env = NULL; - const char *ldpreload_env = NULL; - - /* NOTE: we store the elfdata pointer on a special location - * of the temporary TLS area in order to pass it to - * the C Library's runtime initializer. - * - * The initializer must clear the slot and reset the TLS - * to point to a different location to ensure that no other - * shared library constructor can access it. - */ -#if 0 - __libc_init_tls(elfdata); -#endif - - pid = getpid(); - -#if TIMING - struct timeval t0, t1; - gettimeofday(&t0, 0); -#endif - - /* Initialize environment functions, and get to the ELF aux vectors table */ - vecs = linker_env_init(vecs); - - /* Check auxv for AT_SECURE first to see if program is setuid, setgid, - has file caps, or caused a SELinux/AppArmor domain transition. */ - for (v = vecs; v[0]; v += 2) { - if (v[0] == AT_SECURE) { - /* kernel told us whether to enable secure mode */ - program_is_setuid = v[1]; - goto sanitize; - } - } - - /* Kernel did not provide AT_SECURE - fall back on legacy test. */ - program_is_setuid = (getuid() != geteuid()) || (getgid() != getegid()); - -sanitize: - /* Sanitize environment if we're loading a setuid program */ - if (program_is_setuid) - linker_env_secure(); - -#if 0 - debugger_init(); -#endif - - /* Get a few environment variables */ - { -#if LINKER_DEBUG - const char* env; - env = linker_env_get("DEBUG"); /* XXX: TODO: Change to LD_DEBUG */ - if (env) - debug_verbosity = atoi(env); -#endif - - /* Normally, these are cleaned by linker_env_secure, but the test - * against program_is_setuid doesn't cost us anything */ - if (!program_is_setuid) { - ldpath_env = getenv("LD_LIBRARY_PATH"); - ldpreload_env = getenv("LD_PRELOAD"); - } - } - - INFO("[ android linker & debugger ]\n"); - DEBUG("%5d elfdata @ 0x%08x\n", pid, (unsigned)elfdata); - - si = alloc_info(argv[0]); - if(si == 0) { - exit(-1); - } - - /* bootstrap the link map, the main exe always needs to be first */ - si->flags |= FLAG_EXE; - map = &(si->linkmap); - - map->l_addr = 0; - map->l_name = argv[0]; - map->l_prev = NULL; - map->l_next = NULL; - - _r_debug.r_map = map; - r_debug_tail = map; - - /* gdb expects the linker to be in the debug shared object list, - * and we need to make sure that the reported load address is zero. - * Without this, gdb gets the wrong idea of where rtld_db_dlactivity() - * is. Don't use alloc_info(), because the linker shouldn't - * be on the soinfo list. - */ - strlcpy((char*) linker_soinfo.name, "/system/bin/linker", sizeof linker_soinfo.name); - linker_soinfo.flags = 0; - linker_soinfo.base = 0; // This is the important part; must be zero. - insert_soinfo_into_debug_map(&linker_soinfo); - - /* extract information passed from the kernel */ - while(vecs[0] != 0){ - switch(vecs[0]){ - case AT_PHDR: - si->phdr = (Elf32_Phdr*) vecs[1]; - break; - case AT_PHNUM: - si->phnum = (int) vecs[1]; - break; - case AT_ENTRY: - si->entry = vecs[1]; - break; - } - vecs += 2; - } - - /* 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) - */ - int nn; - 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; - break; - } - } - si->dynamic = (unsigned *)-1; - si->wrprotect_start = 0xffffffff; - si->wrprotect_end = 0; - si->refcount = 1; - si->gnu_relro_start = 0; - si->gnu_relro_len = 0; - - /* Use LD_LIBRARY_PATH if we aren't setuid/setgid */ - if (ldpath_env) - parse_library_path(ldpath_env, ":"); - - if (ldpreload_env) { - parse_preloads(ldpreload_env, " :"); - } - - if(link_image(si, 0)) { - char errmsg[] = "CANNOT LINK EXECUTABLE\n"; - write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf)); - write(2, errmsg, sizeof(errmsg)); - exit(-1); - } - - call_constructors_recursive(si); - -#if ALLOW_SYMBOLS_FROM_MAIN - /* Set somain after we've loaded all the libraries in order to prevent - * linking of symbols back to the main image, which is not set up at that - * point yet. - */ - somain = si; -#endif - -#if TIMING - gettimeofday(&t1,NULL); - PRINT("LINKER TIME: %s: %d microseconds\n", 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\n", argv[0], - linker_stats.reloc[RELOC_ABSOLUTE], - linker_stats.reloc[RELOC_RELATIVE], - linker_stats.reloc[RELOC_COPY], - linker_stats.reloc[RELOC_SYMBOL]); -#endif -#if COUNT_PAGES - { - unsigned n; - unsigned i; - unsigned count = 0; - for(n = 0; n < 4096; n++){ - if(bitmask[n]){ - unsigned x = bitmask[n]; - for(i = 0; i < 8; i++){ - if(x & 1) count++; - x >>= 1; - } - } - } - PRINT("PAGES MODIFIED: %s: %d (%dKB)\n", argv[0], count, count * 4); - } -#endif - -#if TIMING || STATS || COUNT_PAGES - fflush(stdout); -#endif - - TRACE("[ %5d Ready to execute '%s' @ 0x%08x ]\n", pid, si->name, - si->entry); - return si->entry; -} - -/* - * Find the value of AT_BASE passed to us by the kernel. This is the load - * location of the linker. - */ -static unsigned find_linker_base(unsigned **elfdata) { - int argc = (int) *elfdata; - char **argv = (char**) (elfdata + 1); - unsigned *vecs = (unsigned*) (argv + argc + 1); - while (vecs[0] != 0) { - vecs++; - } - - /* The end of the environment block is marked by two NULL pointers */ - vecs++; - - while(vecs[0]) { - if (vecs[0] == AT_BASE) { - return vecs[1]; - } - vecs += 2; - } - - return 0; // should never happen -} - -/* - * 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. - */ -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); - - soinfo linker_so; - memset(&linker_so, 0, sizeof(soinfo)); - - linker_so.base = linker_addr; - linker_so.dynamic = (unsigned *) -1; - linker_so.phdr = phdr; - linker_so.phnum = elf_hdr->e_phnum; - linker_so.flags |= FLAG_LINKER; - linker_so.wrprotect_start = 0xffffffff; - linker_so.wrprotect_end = 0; - linker_so.gnu_relro_start = 0; - linker_so.gnu_relro_len = 0; - - if (link_image(&linker_so, 0)) { - // 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). - // - // This situation should never occur unless the linker itself - // is corrupt. - exit(-1); - } - - // We have successfully fixed our own relocations. It's safe to run - // the main part of the linker now. - return __linker_init_post_relocation(elfdata); -} diff --git a/hybris/common/gingerbread/linker.h b/hybris/common/gingerbread/linker.h deleted file mode 100644 index e6426ae0d..000000000 --- a/hybris/common/gingerbread/linker.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * 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 -#include -#include - -#undef PAGE_MASK -#undef PAGE_SIZE -#define PAGE_SIZE 4096 -#define PAGE_MASK 4095 - -void debugger_init(); -const char *addr_to_name(unsigned addr); - -/* magic shared structures that GDB knows about */ - -struct link_map -{ - uintptr_t l_addr; - char * l_name; - uintptr_t l_ld; - struct link_map * l_next; - struct link_map * l_prev; -}; - -/* needed for dl_iterate_phdr to be passed to the callbacks provided */ -struct dl_phdr_info -{ - Elf32_Addr dlpi_addr; - const char *dlpi_name; - const Elf32_Phdr *dlpi_phdr; - Elf32_Half dlpi_phnum; -}; - - -// Values for r_debug->state -enum { - RT_CONSISTENT, - RT_ADD, - RT_DELETE -}; - -struct r_debug -{ - int32_t r_version; - struct link_map * r_map; - void (*r_brk)(void); - int32_t r_state; - uintptr_t r_ldbase; -}; - -typedef struct soinfo soinfo; - -#define FLAG_LINKED 0x00000001 -#define FLAG_ERROR 0x00000002 -#define FLAG_EXE 0x00000004 // The main executable -#define FLAG_LINKER 0x00000010 // The linker itself - -#define SOINFO_NAME_LEN 128 - -struct soinfo -{ - const char name[SOINFO_NAME_LEN]; - Elf32_Phdr *phdr; - int phnum; - unsigned entry; - unsigned base; - unsigned size; - - int unused; // DO NOT USE, maintained for compatibility. - - unsigned *dynamic; - - unsigned wrprotect_start; - unsigned wrprotect_end; - - soinfo *next; - unsigned flags; - - const char *strtab; - Elf32_Sym *symtab; - - unsigned nbucket; - unsigned nchain; - unsigned *bucket; - unsigned *chain; - - unsigned *plt_got; - - Elf32_Rel *plt_rel; - unsigned plt_rel_count; - - Elf32_Rel *rel; - unsigned rel_count; - - unsigned *preinit_array; - unsigned preinit_array_count; - - unsigned *init_array; - unsigned init_array_count; - unsigned *fini_array; - unsigned fini_array_count; - - void (*init_func)(void); - void (*fini_func)(void); - -#ifdef ANDROID_ARM_LINKER - /* ARM EABI section used for stack unwinding. */ - unsigned *ARM_exidx; - unsigned ARM_exidx_count; -#endif - - unsigned refcount; - struct link_map linkmap; - - int constructors_called; - - Elf32_Addr gnu_relro_start; - unsigned gnu_relro_len; - -}; - - -extern soinfo libdl_info; - -#ifdef ANDROID_ARM_LINKER - -#define R_ARM_COPY 20 -#define R_ARM_GLOB_DAT 21 -#define R_ARM_JUMP_SLOT 22 -#define R_ARM_RELATIVE 23 - -/* According to the AAPCS specification, we only - * need the above relocations. However, in practice, - * the following ones turn up from time to time. - */ -#define R_ARM_ABS32 2 -#define R_ARM_REL32 3 - -#elif defined(ANDROID_X86_LINKER) - -#define R_386_32 1 -#define R_386_PC32 2 -#define R_386_GLOB_DAT 6 -#define R_386_JUMP_SLOT 7 -#define R_386_RELATIVE 8 - -#endif - -#ifndef DT_INIT_ARRAY -#define DT_INIT_ARRAY 25 -#endif - -#ifndef DT_FINI_ARRAY -#define DT_FINI_ARRAY 26 -#endif - -#ifndef DT_INIT_ARRAYSZ -#define DT_INIT_ARRAYSZ 27 -#endif - -#ifndef DT_FINI_ARRAYSZ -#define DT_FINI_ARRAYSZ 28 -#endif - -#ifndef DT_PREINIT_ARRAY -#define DT_PREINIT_ARRAY 32 -#endif - -#ifndef DT_PREINIT_ARRAYSZ -#define DT_PREINIT_ARRAYSZ 33 -#endif - -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); -soinfo *find_containing_library(const void *addr); -Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si); -const char *linker_get_error(void); -void call_constructors_recursive(soinfo *si); - -#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 diff --git a/hybris/common/gingerbread/linker_debug.h b/hybris/common/gingerbread/linker_debug.h deleted file mode 100644 index 37a27e91d..000000000 --- a/hybris/common/gingerbread/linker_debug.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2008-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 _LINKER_DEBUG_H_ -#define _LINKER_DEBUG_H_ - -#include - -#ifndef LINKER_DEBUG -#error LINKER_DEBUG should be defined to either 1 or 0 in Android.mk -#endif - -/* set LINKER_DEBUG_TO_LOG to 1 to send the logs to logcat, - * or 0 to use stdout instead. - */ -#define LINKER_DEBUG_TO_LOG 0 -#define TRACE_DEBUG 1 -#define DO_TRACE_LOOKUP 1 -#define DO_TRACE_RELO 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 - *********************************************************************/ - - -/*********************************************************************/ -#undef TRUE -#undef FALSE -#define TRUE 1 -#define FALSE 0 - -/* Only use printf() during debugging. We have seen occasional memory - * corruption when the linker uses printf(). - */ -#if LINKER_DEBUG -#include "linker_format.h" -extern int debug_verbosity; -#if LINKER_DEBUG_TO_LOG -extern int format_log(int, const char *, const char *, ...); -#define _PRINTVF(v,f,x...) \ - do { \ - if (debug_verbosity > (v)) format_log(5-(v),"linker",x); \ - } while (0) -#else /* !LINKER_DEBUG_TO_LOG */ -extern int format_fd(int, const char *, ...); -#define _PRINTVF(v,f,x...) \ - do { \ - if (debug_verbosity > (v)) format_fd(1, x); \ - } while (0) -#endif /* !LINKER_DEBUG_TO_LOG */ -#else /* !LINKER_DEBUG */ -#define _PRINTVF(v,f,x...) do {} while(0) -#endif /* LINKER_DEBUG */ - -#define PRINT(x...) _PRINTVF(-1, FALSE, x) -#define INFO(x...) _PRINTVF(1, TRUE, x) -#define TRACE(x...) _PRINTVF(1, TRUE, x) -#define WARN(fmt,args...) \ - _PRINTVF(-1, TRUE, "%s:%d| WARNING: " fmt, __FILE__, __LINE__, ## args) -#define ERROR(fmt,args...) \ - _PRINTVF(-1, TRUE, "%s:%d| ERROR: " fmt, __FILE__, __LINE__, ## args) - - -#if TRACE_DEBUG -#define DEBUG(x...) _PRINTVF(2, TRUE, "DEBUG: " x) -#else /* !TRACE_DEBUG */ -#define DEBUG(x...) do {} while (0) -#endif /* TRACE_DEBUG */ - -#if LINKER_DEBUG -#define TRACE_TYPE(t,x...) do { if (DO_TRACE_##t) { TRACE(x); } } while (0) -#else /* !LINKER_DEBUG */ -#define TRACE_TYPE(t,x...) do {} while (0) -#endif /* LINKER_DEBUG */ - -#if STATS -#define RELOC_ABSOLUTE 0 -#define RELOC_RELATIVE 1 -#define RELOC_COPY 2 -#define RELOC_SYMBOL 3 -#define NUM_RELOC_STATS 4 - -struct _link_stats { - int reloc[NUM_RELOC_STATS]; -}; -extern struct _link_stats linker_stats; - -#define COUNT_RELOC(type) \ - do { if (type >= 0 && type < NUM_RELOC_STATS) { \ - linker_stats.reloc[type] += 1; \ - } else { \ - PRINT("Unknown reloc stat requested\n"); \ - } \ - } while(0) -#else /* !STATS */ -#define COUNT_RELOC(type) do {} while(0) -#endif /* STATS */ - -#if TIMING -#undef WARN -#define WARN(x...) do {} while (0) -#endif /* TIMING */ - -#if COUNT_PAGES -extern unsigned bitmask[]; -#define MARK(offset) do { \ - bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \ - } while(0) -#else -#define MARK(x) do {} while (0) -#endif - -#define DEBUG_DUMP_PHDR(phdr, name, pid) do { \ - DEBUG("%5d %s (phdr = 0x%08x)\n", (pid), (name), (unsigned)(phdr)); \ - DEBUG("\t\tphdr->offset = 0x%08x\n", (unsigned)((phdr)->p_offset)); \ - DEBUG("\t\tphdr->p_vaddr = 0x%08x\n", (unsigned)((phdr)->p_vaddr)); \ - DEBUG("\t\tphdr->p_paddr = 0x%08x\n", (unsigned)((phdr)->p_paddr)); \ - DEBUG("\t\tphdr->p_filesz = 0x%08x\n", (unsigned)((phdr)->p_filesz)); \ - DEBUG("\t\tphdr->p_memsz = 0x%08x\n", (unsigned)((phdr)->p_memsz)); \ - DEBUG("\t\tphdr->p_flags = 0x%08x\n", (unsigned)((phdr)->p_flags)); \ - DEBUG("\t\tphdr->p_align = 0x%08x\n", (unsigned)((phdr)->p_align)); \ - } while (0) - -#endif /* _LINKER_DEBUG_H_ */ diff --git a/hybris/common/gingerbread/linker_environ.c b/hybris/common/gingerbread/linker_environ.c deleted file mode 100644 index b71dd8069..000000000 --- a/hybris/common/gingerbread/linker_environ.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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. - */ -#include "linker_environ.h" -#include - -static char** _envp; - -/* Returns 1 if 'str' points to a valid environment variable definition. - * For now, we check that: - * - It is smaller than MAX_ENV_LEN (to detect non-zero terminated strings) - * - It contains at least one equal sign that is not the first character - */ -static int -_is_valid_definition(const char* str) -{ - int pos = 0; - int first_equal_pos = -1; - - /* According to its sources, the kernel uses 32*PAGE_SIZE by default - * as the maximum size for an env. variable definition. - */ - const int MAX_ENV_LEN = 32*4096; - - if (str == NULL) - return 0; - - /* Parse the string, looking for the first '=' there, and its size */ - do { - if (str[pos] == '\0') - break; - if (str[pos] == '=' && first_equal_pos < 0) - first_equal_pos = pos; - pos++; - } while (pos < MAX_ENV_LEN); - - if (pos >= MAX_ENV_LEN) /* Too large */ - return 0; - - if (first_equal_pos < 1) /* No equal sign, or it is the first character */ - return 0; - - return 1; -} - -unsigned* -linker_env_init(unsigned* vecs) -{ - /* Store environment pointer - can't be NULL */ - _envp = (char**) vecs; - - /* Skip over all definitions */ - while (vecs[0] != 0) - vecs++; - /* The end of the environment block is marked by two NULL pointers */ - vecs++; - - /* As a sanity check, we're going to remove all invalid variable - * definitions from the environment array. - */ - { - char** readp = _envp; - char** writep = _envp; - for ( ; readp[0] != NULL; readp++ ) { - if (!_is_valid_definition(readp[0])) - continue; - writep[0] = readp[0]; - writep++; - } - writep[0] = NULL; - } - - /* Return the address of the aux vectors table */ - return vecs; -} - -/* Check if the environment variable definition at 'envstr' - * starts with '=', and if so return the address of the - * first character after the equal sign. Otherwise return NULL. - */ -static char* -env_match(char* envstr, const char* name) -{ - size_t cnt = 0; - - while (envstr[cnt] == name[cnt] && name[cnt] != '\0') - cnt++; - - if (name[cnt] == '\0' && envstr[cnt] == '=') - return envstr + cnt + 1; - - return NULL; -} - -#define MAX_ENV_LEN (16*4096) - -const char* -linker_env_get(const char* name) -{ - char** readp = _envp; - - if (name == NULL || name[0] == '\0') - return NULL; - - for ( ; readp[0] != NULL; readp++ ) { - char* val = env_match(readp[0], name); - if (val != NULL) { - /* Return NULL for empty strings, or if it is too large */ - if (val[0] == '\0') - val = NULL; - return val; - } - } - return NULL; -} - - -void -linker_env_unset(const char* name) -{ - char** readp = _envp; - char** writep = readp; - - if (name == NULL || name[0] == '\0') - return; - - for ( ; readp[0] != NULL; readp++ ) { - if (env_match(readp[0], name)) - continue; - writep[0] = readp[0]; - writep++; - } - /* end list with a NULL */ - writep[0] = NULL; -} - - - -/* Remove unsafe environment variables. This should be used when - * running setuid programs. */ -void -linker_env_secure(void) -{ - /* The same list than GLibc at this point */ - static const char* const unsec_vars[] = { - "GCONV_PATH", - "GETCONF_DIR", - "HOSTALIASES", - "LD_AUDIT", - "LD_DEBUG", - "LD_DEBUG_OUTPUT", - "LD_DYNAMIC_WEAK", - "LD_LIBRARY_PATH", - "LD_ORIGIN_PATH", - "LD_PRELOAD", - "LD_PROFILE", - "LD_SHOW_AUXV", - "LD_USE_LOAD_BIAS", - "LOCALDOMAIN", - "LOCPATH", - "MALLOC_TRACE", - "MALLOC_CHECK_", - "NIS_PATH", - "NLSPATH", - "RESOLV_HOST_CONF", - "RES_OPTIONS", - "TMPDIR", - "TZDIR", - "LD_AOUT_LIBRARY_PATH", - "LD_AOUT_PRELOAD", - }; - - const char* const* cp = unsec_vars; - const char* const* endp = cp + sizeof(unsec_vars)/sizeof(unsec_vars[0]); - - while (cp < endp) { - linker_env_unset(*cp); - cp++; - } -} diff --git a/hybris/common/gingerbread/linker_environ.h b/hybris/common/gingerbread/linker_environ.h deleted file mode 100644 index 98ad1de27..000000000 --- a/hybris/common/gingerbread/linker_environ.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 LINKER_ENVIRON_H -#define LINKER_ENVIRON_H - -/* Call this function before anything else. 'vecs' must be the pointer - * to the environment block in the ELF data block. The function returns - * the start of the aux vectors after the env block. - */ -extern unsigned* linker_env_init(unsigned* vecs); - -/* Unset a given environment variable. In case the variable is defined - * multiple times, unset all instances. This modifies the environment - * block, so any pointer returned by linker_env_get() after this call - * might become invalid */ -extern void linker_env_unset(const char* name); - - -/* Returns the value of environment variable 'name' if defined and not - * empty, or NULL otherwise. Note that the returned pointer may become - * invalid if linker_env_unset() or linker_env_secure() are called - * after this function. */ -extern const char* linker_env_get(const char* name); - -/* Remove unsecure environment variables. This should be used when - * running setuid programs. */ -extern void linker_env_secure(void); - -#endif /* LINKER_ENVIRON_H */ diff --git a/hybris/common/gingerbread/linker_format.c b/hybris/common/gingerbread/linker_format.c deleted file mode 100644 index 92ece21c2..000000000 --- a/hybris/common/gingerbread/linker_format.c +++ /dev/null @@ -1,707 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include "linker_format.h" -#include "linker_debug.h" - -/* define UNIT_TESTS to build this file as a single executable that runs - * the formatter's unit tests - */ -#define xxUNIT_TESTS - -/*** Generic output sink - ***/ - -typedef struct { - void *opaque; - void (*send)(void *opaque, const char *data, int len); -} Out; - -static void -out_send(Out *o, const void *data, size_t len) -{ - o->send(o->opaque, data, (int)len); -} - -static void -out_send_repeat(Out *o, char ch, int count) -{ - char pad[8]; - const int padSize = (int)sizeof(pad); - - memset(pad, ch, sizeof(pad)); - while (count > 0) { - int avail = count; - if (avail > padSize) { - avail = padSize; - } - o->send(o->opaque, pad, avail); - count -= avail; - } -} - -/* forward declaration */ -static void -out_vformat(Out *o, const char *format, va_list args); - -/*** Bounded buffer output - ***/ - -typedef struct { - Out out[1]; - char *buffer; - char *pos; - char *end; - int total; -} BufOut; - -static void -buf_out_send(void *opaque, const char *data, int len) -{ - BufOut *bo = opaque; - - if (len < 0) - len = strlen(data); - - bo->total += len; - - while (len > 0) { - int avail = bo->end - bo->pos; - if (avail == 0) - break; - if (avail > len) - avail = len; - memcpy(bo->pos, data, avail); - bo->pos += avail; - bo->pos[0] = '\0'; - len -= avail; - } -} - -static Out* -buf_out_init(BufOut *bo, char *buffer, size_t size) -{ - if (size == 0) - return NULL; - - bo->out->opaque = bo; - bo->out->send = buf_out_send; - bo->buffer = buffer; - bo->end = buffer + size - 1; - bo->pos = bo->buffer; - bo->pos[0] = '\0'; - bo->total = 0; - - return bo->out; -} - -static int -buf_out_length(BufOut *bo) -{ - return bo->total; -} - -static int -vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args) -{ - BufOut bo; - Out *out; - - out = buf_out_init(&bo, buff, buffsize); - if (out == NULL) - return 0; - - out_vformat(out, format, args); - - return buf_out_length(&bo); -} - -int -format_buffer(char *buff, size_t buffsize, const char *format, ...) -{ - va_list args; - int ret; - - va_start(args, format); - ret = vformat_buffer(buff, buffsize, format, args); - va_end(args); - - return ret; -} - -/* The __stack_chk_fail() function calls __libc_android_log_print() - * which calls vsnprintf(). - * - * We define our version of the function here to avoid dragging - * about 25 KB of C library routines related to formatting. - */ -#if 0 -int -vsnprintf(char *buff, size_t bufsize, const char *format, va_list args) -{ - return format_buffer(buff, bufsize, format, args); -} -#endif - -#if LINKER_DEBUG - -#if !LINKER_DEBUG_TO_LOG - -/*** File descriptor output - ***/ - -typedef struct { - Out out[1]; - int fd; - int total; -} FdOut; - -static void -fd_out_send(void *opaque, const char *data, int len) -{ - FdOut *fdo = opaque; - - if (len < 0) - len = strlen(data); - - while (len > 0) { - int ret = write(fdo->fd, data, len); - if (ret < 0) { - if (errno == EINTR) - continue; - break; - } - data += ret; - len -= ret; - fdo->total += ret; - } -} - -static Out* -fd_out_init(FdOut *fdo, int fd) -{ - fdo->out->opaque = fdo; - fdo->out->send = fd_out_send; - fdo->fd = fd; - fdo->total = 0; - - return fdo->out; -} - -static int -fd_out_length(FdOut *fdo) -{ - return fdo->total; -} - - -int -format_fd(int fd, const char *format, ...) -{ - FdOut fdo; - Out* out; - va_list args; - - out = fd_out_init(&fdo, fd); - if (out == NULL) - return 0; - - va_start(args, format); - out_vformat(out, format, args); - va_end(args); - - return fd_out_length(&fdo); -} - -#else /* LINKER_DEBUG_TO_LOG */ - -/*** Log output - ***/ - -/* We need our own version of __libc_android_log_vprint, otherwise - * the log output is completely broken. Probably due to the fact - * that the C library is not initialized yet. - * - * You can test that by setting CUSTOM_LOG_VPRINT to 0 - */ -#define CUSTOM_LOG_VPRINT 1 - -#if CUSTOM_LOG_VPRINT - -#include -#include -#include - -static int log_vprint(int prio, const char *tag, const char *fmt, va_list args) -{ - char buf[1024]; - int result; - static int log_fd = -1; - - result = vformat_buffer(buf, sizeof buf, fmt, args); - - if (log_fd < 0) { - log_fd = open("/dev/log/main", O_WRONLY); - if (log_fd < 0) - return result; - } - - { - ssize_t ret; - struct iovec vec[3]; - - vec[0].iov_base = (unsigned char *) &prio; - vec[0].iov_len = 1; - vec[1].iov_base = (void *) tag; - vec[1].iov_len = strlen(tag) + 1; - vec[2].iov_base = (void *) buf; - vec[2].iov_len = strlen(buf) + 1; - - do { - ret = writev(log_fd, vec, 3); - } while ((ret < 0) && (errno == EINTR)); - } - return result; -} - -#define __libc_android_log_vprint log_vprint - -#else /* !CUSTOM_LOG_VPRINT */ - -extern int __libc_android_log_vprint(int prio, const char* tag, const char* format, va_list ap); - -#endif /* !CUSTOM_LOG_VPRINT */ - -int -format_log(int prio, const char *tag, const char *format, ...) -{ - int ret; - va_list args; - va_start(args, format); - ret = __libc_android_log_vprint(prio, tag, format, args); - va_end(args); - return ret; -} - -#endif /* LINKER_DEBUG_TO_LOG */ - -#endif /* LINKER_DEBUG */ - -/*** formatted output implementation - ***/ - -/* Parse a decimal string from 'format + *ppos', - * return the value, and writes the new position past - * the decimal string in '*ppos' on exit. - * - * NOTE: Does *not* handle a sign prefix. - */ -static unsigned -parse_decimal(const char *format, int *ppos) -{ - const char* p = format + *ppos; - unsigned result = 0; - - for (;;) { - int ch = *p; - unsigned d = (unsigned)(ch - '0'); - - if (d >= 10U) - break; - - result = result*10 + d; - p++; - } - *ppos = p - format; - return result; -} - -/* write an octal/decimal/number into a bounded buffer. - * assumes that bufsize > 0, and 'digits' is a string of - * digits of at least 'base' values. - */ -static void -format_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits) -{ - char *pos = buffer; - char *end = buffer + bufsize - 1; - - /* generate digit string in reverse order */ - while (value) { - unsigned d = value % base; - value /= base; - if (pos < end) { - *pos++ = digits[d]; - } - } - - /* special case for 0 */ - if (pos == buffer) { - if (pos < end) { - *pos++ = '0'; - } - } - pos[0] = '\0'; - - /* now reverse digit string in-place */ - end = pos - 1; - pos = buffer; - while (pos < end) { - int ch = pos[0]; - pos[0] = end[0]; - end[0] = (char) ch; - pos++; - end--; - } -} - -/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */ -static void -format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned) -{ - if (isSigned && (int64_t)value < 0) { - buffer[0] = '-'; - buffer += 1; - buffsize -= 1; - value = (uint64_t)(-(int64_t)value); - } - - format_number(buffer, buffsize, value, base, "0123456789"); -} - -/* Write an octal into a buffer, assumes buffsize > 2 */ -static void -format_octal(char *buffer, size_t buffsize, uint64_t value, int isSigned) -{ - format_integer(buffer, buffsize, value, 8, isSigned); -} - -/* Write a decimal into a buffer, assumes buffsize > 2 */ -static void -format_decimal(char *buffer, size_t buffsize, uint64_t value, int isSigned) -{ - format_integer(buffer, buffsize, value, 10, isSigned); -} - -/* Write an hexadecimal into a buffer, isCap is true for capital alphas. - * Assumes bufsize > 2 */ -static void -format_hex(char *buffer, size_t buffsize, uint64_t value, int isCap) -{ - const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef"; - - format_number(buffer, buffsize, value, 16, digits); -} - - -/* Perform formatted output to an output target 'o' */ -static void -out_vformat(Out *o, const char *format, va_list args) -{ - int nn = 0; - - for (;;) { - int mm; - int padZero = 0; - int padLeft = 0; - char sign = '\0'; - int width = -1; - int prec = -1; - size_t bytelen = sizeof(int); - const char* str; - int slen; - char buffer[32]; /* temporary buffer used to format numbers */ - - char c; - - /* first, find all characters that are not 0 or '%' */ - /* then send them to the output directly */ - mm = nn; - do { - c = format[mm]; - if (c == '\0' || c == '%') - break; - mm++; - } while (1); - - if (mm > nn) { - out_send(o, format+nn, mm-nn); - nn = mm; - } - - /* is this it ? then exit */ - if (c == '\0') - break; - - /* nope, we are at a '%' modifier */ - nn++; // skip it - - /* parse flags */ - for (;;) { - c = format[nn++]; - if (c == '\0') { /* single trailing '%' ? */ - c = '%'; - out_send(o, &c, 1); - return; - } - else if (c == '0') { - padZero = 1; - continue; - } - else if (c == '-') { - padLeft = 1; - continue; - } - else if (c == ' ' || c == '+') { - sign = c; - continue; - } - break; - } - - /* parse field width */ - if ((c >= '0' && c <= '9')) { - nn --; - width = (int)parse_decimal(format, &nn); - c = format[nn++]; - } - - /* parse precision */ - if (c == '.') { - prec = (int)parse_decimal(format, &nn); - c = format[nn++]; - } - - /* length modifier */ - switch (c) { - case 'h': - bytelen = sizeof(short); - if (format[nn] == 'h') { - bytelen = sizeof(char); - nn += 1; - } - c = format[nn++]; - break; - case 'l': - bytelen = sizeof(long); - if (format[nn] == 'l') { - bytelen = sizeof(long long); - nn += 1; - } - c = format[nn++]; - break; - case 'z': - bytelen = sizeof(size_t); - c = format[nn++]; - break; - case 't': - bytelen = sizeof(ptrdiff_t); - c = format[nn++]; - break; - default: - ; - } - - /* conversion specifier */ - if (c == 's') { - /* string */ - str = va_arg(args, const char*); - } else if (c == 'c') { - /* character */ - /* NOTE: char is promoted to int when passed through the stack */ - buffer[0] = (char) va_arg(args, int); - buffer[1] = '\0'; - str = buffer; - } else if (c == 'p') { - uint64_t value = (uintptr_t) va_arg(args, void*); - buffer[0] = '0'; - buffer[1] = 'x'; - format_hex(buffer + 2, sizeof buffer-2, value, 0); - str = buffer; - } else { - /* integers - first read value from stack */ - uint64_t value; - int isSigned = (c == 'd' || c == 'i' || c == 'o'); - - /* NOTE: int8_t and int16_t are promoted to int when passed - * through the stack - */ - switch (bytelen) { - case 1: value = (uint8_t) va_arg(args, int); break; - case 2: value = (uint16_t) va_arg(args, int); break; - case 4: value = va_arg(args, uint32_t); break; - case 8: value = va_arg(args, uint64_t); break; - default: return; /* should not happen */ - } - - /* sign extension, if needed */ - if (isSigned) { - int shift = 64 - 8*bytelen; - value = (uint64_t)(((int64_t)(value << shift)) >> shift); - } - - /* format the number properly into our buffer */ - switch (c) { - case 'i': case 'd': - format_integer(buffer, sizeof buffer, value, 10, isSigned); - break; - case 'o': - format_integer(buffer, sizeof buffer, value, 8, isSigned); - break; - case 'x': case 'X': - format_hex(buffer, sizeof buffer, value, (c == 'X')); - break; - default: - buffer[0] = '\0'; - } - /* then point to it */ - str = buffer; - } - - /* if we are here, 'str' points to the content that must be - * outputted. handle padding and alignment now */ - - slen = strlen(str); - - if (slen < width && !padLeft) { - char padChar = padZero ? '0' : ' '; - out_send_repeat(o, padChar, width - slen); - } - - out_send(o, str, slen); - - if (slen < width && padLeft) { - char padChar = padZero ? '0' : ' '; - out_send_repeat(o, padChar, width - slen); - } - } -} - - -#ifdef UNIT_TESTS - -#include - -static int gFails = 0; - -#define MARGIN 40 - -#define UTEST_CHECK(condition,message) \ - printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \ - if (!(condition)) { \ - printf("KO\n"); \ - gFails += 1; \ - } else { \ - printf("ok\n"); \ - } - -static void -utest_BufOut(void) -{ - char buffer[16]; - BufOut bo[1]; - Out* out; - int ret; - - buffer[0] = '1'; - out = buf_out_init(bo, buffer, sizeof buffer); - UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte"); - out_send(out, "abc", 3); - UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut"); - out_send_repeat(out, 'X', 4); - UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut"); - buffer[sizeof buffer-1] = 'x'; - out_send_repeat(out, 'Y', 2*sizeof(buffer)); - UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates"); - - out = buf_out_init(bo, buffer, sizeof buffer); - out_send_repeat(out, 'X', 2*sizeof(buffer)); - ret = buf_out_length(bo); - UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow"); -} - -static void -utest_expect(const char* result, const char* format, ...) -{ - va_list args; - BufOut bo[1]; - char buffer[256]; - Out* out = buf_out_init(bo, buffer, sizeof buffer); - - printf("Checking %-*s: ", MARGIN, format); fflush(stdout); - va_start(args, format); - out_vformat(out, format, args); - va_end(args); - - if (strcmp(result, buffer)) { - printf("KO. got '%s' expecting '%s'\n", buffer, result); - gFails += 1; - } else { - printf("ok. got '%s'\n", result); - } -} - -int main(void) -{ - utest_BufOut(); - utest_expect("", ""); - utest_expect("a", "a"); - utest_expect("01234", "01234", ""); - utest_expect("01234", "%s", "01234"); - utest_expect("aabbcc", "aa%scc", "bb"); - utest_expect("a", "%c", 'a'); - utest_expect("1234", "%d", 1234); - utest_expect("-8123", "%d", -8123); - utest_expect("16", "%hd", 0x7fff0010); - utest_expect("16", "%hhd", 0x7fffff10); - utest_expect("68719476736", "%lld", 0x1000000000LL); - utest_expect("70000", "%ld", 70000); - utest_expect("0xb0001234", "%p", (void*)0xb0001234); - utest_expect("12ab", "%x", 0x12ab); - utest_expect("12AB", "%X", 0x12ab); - utest_expect("00123456", "%08x", 0x123456); - utest_expect("01234", "0%d", 1234); - utest_expect(" 1234", "%5d", 1234); - utest_expect("01234", "%05d", 1234); - utest_expect(" 1234", "%8d", 1234); - utest_expect("1234 ", "%-8d", 1234); - utest_expect("abcdef ", "%-11s", "abcdef"); - utest_expect("something:1234", "%s:%d", "something", 1234); - utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5); - utest_expect("5,0x0", "%d,%p", 5, NULL); - utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8); - return gFails != 0; -} - -#endif /* UNIT_TESTS */ diff --git a/hybris/common/gingerbread/patches/gingerbread-bionic.patch b/hybris/common/gingerbread/patches/gingerbread-bionic.patch deleted file mode 100644 index 5b875f5ca..000000000 --- a/hybris/common/gingerbread/patches/gingerbread-bionic.patch +++ /dev/null @@ -1,298 +0,0 @@ -diff --git a/libc/bionic/__errno.c b/libc/bionic/__errno.c -index 8f33cce..34664c6 100644 ---- a/libc/bionic/__errno.c -+++ b/libc/bionic/__errno.c -@@ -28,7 +28,4 @@ - #include - #include - --volatile int* __errno( void ) --{ -- return &((volatile int*)__get_tls())[TLS_SLOT_ERRNO]; --} -+ -diff --git a/libc/bionic/__set_errno.c b/libc/bionic/__set_errno.c -index c72d4f7..529a4ef 100644 ---- a/libc/bionic/__set_errno.c -+++ b/libc/bionic/__set_errno.c -@@ -28,13 +28,6 @@ - - #include - -- --int __set_errno(int n) --{ -- errno = n; -- return -1; --} -- - /* - * this function is called from syscall stubs, - * (tail-called in the case of 0-4 arg versions) -diff --git a/libc/bionic/pthread-rwlocks.c b/libc/bionic/pthread-rwlocks.c -index ca3e95c..1494523 100644 ---- a/libc/bionic/pthread-rwlocks.c -+++ b/libc/bionic/pthread-rwlocks.c -@@ -69,6 +69,8 @@ static int __get_thread_id(void) - - int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) - { -+ -+ abort(); - if (!attr) - return EINVAL; - -@@ -77,8 +79,9 @@ int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) - } - - int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) --{ -- if (!attr) -+{ -+ abort(); -+ if (!attr) - return EINVAL; - - *attr = -1; -@@ -87,6 +90,7 @@ int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr) - - int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared) - { -+ abort(); - if (!attr) - return EINVAL; - -@@ -102,6 +106,8 @@ int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared) - - int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *attr, int *pshared) - { -+ abort(); -+ - if (!attr || !pshared) - return EINVAL; - -@@ -111,6 +117,7 @@ int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *attr, int *pshared) - - int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) - { -+ abort(); - pthread_mutexattr_t* lock_attr = NULL; - pthread_condattr_t* cond_attr = NULL; - pthread_mutexattr_t lock_attr0; -@@ -150,6 +157,10 @@ int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *at - - int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) - { -+ abort(); -+ -+ -+ - int ret; - - if (rwlock == NULL) -@@ -209,11 +220,14 @@ static void _pthread_rwlock_pulse(pthread_rwlock_t *rwlock) - - int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) - { -+ abort(); - return pthread_rwlock_timedrdlock(rwlock, NULL); - } - - int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) - { -+ abort(); -+ - int ret = 0; - - if (rwlock == NULL) -@@ -231,6 +245,7 @@ int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock) - - int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *abs_timeout) - { -+ abort(); - int thread_id, ret = 0; - - if (rwlock == NULL) -@@ -256,11 +271,14 @@ EXIT: - - int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) - { -+ abort(); -+ - return pthread_rwlock_timedwrlock(rwlock, NULL); - } - - int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) - { -+ abort(); - int thread_id, ret = 0; - - if (rwlock == NULL) -@@ -280,6 +298,7 @@ int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock) - - int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *abs_timeout) - { -+ abort(); - int thread_id, ret = 0; - - if (rwlock == NULL) -@@ -310,6 +329,8 @@ EXIT: - - int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) - { -+ abort(); -+ - int ret = 0; - - if (rwlock == NULL) -diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c -index 6b01830..490c39f 100644 ---- a/libc/bionic/pthread.c -+++ b/libc/bionic/pthread.c -@@ -177,7 +177,8 @@ __get_stack_base(int *p_stack_size) - - void __init_tls(void** tls, void* thread) - { -- int nn; -+ *((int *) 0) = -1; -+/* int nn; - - ((pthread_internal_t*)thread)->tls = tls; - -@@ -188,7 +189,7 @@ void __init_tls(void** tls, void* thread) - for (nn = TLS_SLOT_ERRNO; nn < BIONIC_TLS_SLOTS; nn++) - tls[nn] = 0; - -- __set_tls( (void*)tls ); -+ __set_tls( (void*)tls ); */ - } - - -@@ -1662,6 +1663,7 @@ static int tlsmap_alloc(tlsmap_t* m, tls_dtor_t dtor) - - int pthread_key_create(pthread_key_t *key, void (*destructor_function)(void *)) - { -+ abort(); - uint32_t err = ENOMEM; - tlsmap_t* map = tlsmap_lock(); - int k = tlsmap_alloc(map, destructor_function); -@@ -1686,6 +1688,7 @@ int pthread_key_create(pthread_key_t *key, void (*destructor_function)(void *)) - */ - int pthread_key_delete(pthread_key_t key) - { -+ abort(); - uint32_t err; - pthread_internal_t* thr; - tlsmap_t* map; -@@ -1730,6 +1733,7 @@ err1: - - int pthread_setspecific(pthread_key_t key, const void *ptr) - { -+ abort(); - int err = EINVAL; - tlsmap_t* map; - -@@ -1747,6 +1751,7 @@ int pthread_setspecific(pthread_key_t key, const void *ptr) - - void * pthread_getspecific(pthread_key_t key) - { -+ abort(); - if (!TLSMAP_VALIDATE_KEY(key)) { - return NULL; - } -@@ -1775,6 +1780,7 @@ void * pthread_getspecific(pthread_key_t key) - */ - static void pthread_key_clean_all(void) - { -+ abort(); - tlsmap_t* map; - void** tls = (void**)__get_tls(); - int rounds = PTHREAD_DESTRUCTOR_ITERATIONS; -@@ -1830,6 +1836,7 @@ extern int tkill(int tid, int sig); - - int pthread_kill(pthread_t tid, int sig) - { -+ abort(); - int ret; - int old_errno = errno; - pthread_internal_t * thread = (pthread_internal_t *)tid; -@@ -1847,6 +1854,7 @@ extern int __rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t); - - int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) - { -+ abort(); - /* pthread_sigmask must return the error code, but the syscall - * will set errno instead and return 0/-1 - */ -@@ -1863,6 +1871,7 @@ int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) - - int pthread_getcpuclockid(pthread_t tid, clockid_t *clockid) - { -+ abort(); - const int CLOCK_IDTYPE_BITS = 3; - pthread_internal_t* thread = (pthread_internal_t*)tid; - -@@ -1879,6 +1888,7 @@ int pthread_getcpuclockid(pthread_t tid, clockid_t *clockid) - */ - int pthread_once( pthread_once_t* once_control, void (*init_routine)(void) ) - { -+ abort(); - static pthread_mutex_t once_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; - - if (*once_control == PTHREAD_ONCE_INIT) { -@@ -1898,6 +1908,7 @@ int pthread_once( pthread_once_t* once_control, void (*init_routine)(void) ) - - int pthread_setname_np(pthread_t thid, const char *thname) - { -+ abort(); - size_t thname_len; - int saved_errno, ret; - -diff --git a/libc/private/bionic_tls.h b/libc/private/bionic_tls.h -index 94a81cd..81c5e16 100644 ---- a/libc/private/bionic_tls.h -+++ b/libc/private/bionic_tls.h -@@ -55,17 +55,17 @@ __BEGIN_DECLS - /* Well known TLS slots */ - #define TLS_SLOT_SELF 0 - #define TLS_SLOT_THREAD_ID 1 --#define TLS_SLOT_ERRNO 2 -+#define TLS_SLOT_ERRNO 4 - --#define TLS_SLOT_OPENGL_API 3 --#define TLS_SLOT_OPENGL 4 -+#define TLS_SLOT_OPENGL_API 5 -+#define TLS_SLOT_OPENGL 6 - - /* 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. - */ --#define TLS_SLOT_BIONIC_PREINIT (TLS_SLOT_ERRNO+1) -+#define TLS_SLOT_BIONIC_PREINIT 3 - - /* small technical note: it is not possible to call pthread_setspecific - * on keys that are <= TLS_SLOT_MAX_WELL_KNOWN, which is why it is set to -@@ -76,7 +76,7 @@ __BEGIN_DECLS - * pthread_key_create() to initialize them. on the other hand, there is - * no destructor associated to them (we might need to implement this later) - */ --#define TLS_SLOT_MAX_WELL_KNOWN TLS_SLOT_ERRNO -+#define TLS_SLOT_MAX_WELL_KNOWN 2 - - #define TLS_DEFAULT_ALLOC_MAP 0x0000001F - -diff --git a/libdl/libdl.c b/libdl/libdl.c -index b36af16..ad6d4b4 100644 ---- a/libdl/libdl.c -+++ b/libdl/libdl.c -@@ -24,6 +24,8 @@ void *dlsym(void *handle, const char *symbol) { return 0; } - int dladdr(void *addr, Dl_info *info) { return 0; } - int dlclose(void *handle) { return 0; } - -+int *__errno() { return 0; }; -+void __set_errno(int f) {}; - #ifdef __arm__ - void *dl_unwind_find_exidx(void *pc, int *pcount) { return 0; } - #elif defined(__i386__) || defined(__sh__) diff --git a/hybris/common/hooks.c b/hybris/common/hooks.c index 232696280..d4f6a32d0 100644 --- a/hybris/common/hooks.c +++ b/hybris/common/hooks.c @@ -17,18 +17,21 @@ * */ +#include "config.h" + #include #include "hooks_shm.h" -#define _GNU_SOURCE #include #include #include #include #include +#include #include #include +#include #include #include #include @@ -39,22 +42,47 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include #include +#include +#include +#include + #include #include #include #include #include #include +#include + +#include +#include +#include #include +#include 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_mutex(unsigned int mutex_addr) 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_cond(unsigned int cond_addr) (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_init_rwlock(void) * 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) +{ + TRACE_HOOK("size %zu", size); + + void *res = malloc(size); + + TRACE_HOOK("res %p", res); + + return res; +} + +static size_t _hybris_hook_malloc_usable_size (void *ptr) { - return malloc(size); + TRACE_HOOK("ptr %p", ptr); + + return malloc_usable_size(ptr); } -static void *my_memcpy(void *dst, const void *src, size_t len) +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 dst; 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 *thread, const pthread_attr_t *__attr, * * */ -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(pthread_attr_t const *__attr) 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_t thid, pthread_attr_t *__attr) * * */ -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_mutex_t *__mutex, /* 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_mutex_t *__mutex, 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(pthread_mutex_t *__mutex) 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_mutex_t *__mutex) 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(pthread_mutex_t *__mutex) 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(pthread_mutex_t *__mutex) 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_np(pthread_mutex_t *__mutex, unsigned _ 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_np(pthread_mutex_t *__mutex, unsigned _ 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_setpshared(pthread_mutexattr_t *__attr, * * */ -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_cond_t *cond, /* 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_cond_t *cond, 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(pthread_cond_t *cond) 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(pthread_cond_t *cond) 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(pthread_cond_t *cond) 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_cond_t *cond, pthread_mutex_t *mutex) 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_cond_t *cond, pthread_mutex_t *mutex) 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(pthread_cond_t *cond, 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(pthread_cond_t *cond, 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_relative_np(pthread_cond_t *cond, 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_relative_np(pthread_cond_t *cond, 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_relative_np(pthread_cond_t *cond, 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_relative_np(pthread_cond_t *cond, * * */ -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(pthread_rwlockattr_t *__attr) 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_getpshared(pthread_rwlockattr_t *__attr, * * */ -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(pthread_rwlock_t *__rwlock, /* 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(pthread_rwlock_t *__rwlock, 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(pthread_rwlock_t *__rwlock) 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(pthread_rwlock_t *__rwlock) 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, const char *fmt, ...) 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, const char *fmt, ...) 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(DIR *dirp) 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(DIR *dirp) 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,8 +1749,8 @@ static int my_readdir_r(DIR *dir, struct bionic_dirent *entry, return res; } -static int my_alphasort(struct bionic_dirent **a, - struct bionic_dirent **b) +static int _hybris_hook_alphasort(struct bionic_dirent **a, + struct bionic_dirent **b) { return strcoll((*a)->d_name, (*b)->d_name); } @@ -1329,87 +1823,614 @@ static int my_scandir(const char *dir, return my_scandirat(AT_FDCWD, dir, namelist, filter, compar); } -extern long my_sysconf(int name); - -FP_ATTRIB static double my_strtod(const char *nptr, char **endptr) +static int _hybris_hook_versionsort(struct bionic_dirent **a, + struct bionic_dirent **b) { - if (locale_inited == 0) - { - hybris_locale = newlocale(LC_ALL_MASK, "C", 0); - locale_inited = 1; - } - return strtod_l(nptr, endptr, hybris_locale); + return strverscmp((*a)->d_name, (*b)->d_name); } -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/log_main" }, - { "/dev/log/radio", "/dev/log_radio" }, - { "/dev/log/system", "/dev/log_system" }, - { "/dev/log/events", "/dev/log_events" }, - { NULL, NULL } -}; - -int my_open(const char *pathname, int flags, ...) +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 **)) { - va_list ap; - mode_t mode = 0; - const char *target_path = pathname; + struct dirent **namelist_r; + static struct bionic_dirent **result; + struct bionic_dirent *filter_r; - 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++; - } - } + int i = 0; + size_t nItems = 0; - if (flags & O_CREAT) { - va_start(ap, flags); - mode = va_arg(ap, mode_t); - va_end(ap); - } + TRACE_HOOK("parent_fd %d, dir_name %s, namelist %p, filter %p, compar %p", + parent_fd, dir_name, namelist, filter, compar); - return open(target_path, flags, mode); -} + int res = scandirat(parent_fd, dir_name, &namelist_r, NULL, NULL); -/** - * NOTE: Normally we don't have to wrap __system_property_get (libc.so) as it is only used - * through the property_get (libcutils.so) function. However when property_get is used - * internally in libcutils.so we don't have any chance to hook our replacement in. - * Therefore we have to hook __system_property_get too and just replace it with the - * implementation of our internal property handling - */ + if (res != 0 && namelist_r != NULL) { -int my_system_property_get(const char *name, char *value) + 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); +} + +static inline void swap(void **a, void **b) +{ + void *tmp = *a; + *a = *b; + *b = tmp; +} + +static int _hybris_hook_getaddrinfo(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) { - return property_get(name, value, NULL); + struct addrinfo *fixed_hints = NULL; + + TRACE_HOOK("hostname '%s' servname '%s' hints %p res %p", + hostname, servname, hints, res); + + 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); + + 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) +{ + TRACE_HOOK("serial %d", serial); + + return 0; +} + +static const void *___hybris_hook_system_property_find_nth(unsigned n) +{ + TRACE_HOOK("n %d", n); + + return NULL; +} + +/** + * NOTE: Normally we don't have to wrap __system_property_get (libc.so) as it is only used + * through the property_get (libcutils.so) function. However when property_get is used + * internally in libcutils.so we don't have any chance to hook our replacement in. + * Therefore we have to hook __system_property_get too and just replace it with the + * implementation of our internal property handling + */ + +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) +{ + 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; } -static struct _hook hooks[] = { - {"property_get", property_get }, - {"property_set", property_set }, - {"__system_property_get", my_system_property_get }, - {"getenv", getenv }, +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 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 }, @@ -1419,23 +2440,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}, {"getlogin", getlogin}, - // {"memswap",memswap}, + // {"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}, @@ -1444,16 +2466,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}, @@ -1478,11 +2498,11 @@ static struct _hook hooks[] = { {"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}, @@ -1490,72 +2510,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}, @@ -1566,82 +2592,84 @@ 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}, {"scandir", my_scandir}, {"scandirat", my_scandirat}, - {"alphasort", my_alphasort}, + {"alphasort", _hybris_hook_alphasort}, {"versionsort", my_versionsort}, /* fcntl.h */ - {"open", my_open}, - {"__get_tls_hooks", __get_tls_hooks}, + {"open", _hybris_hook_open}, + // TODO: scandir, scandirat, alphasort, versionsort + {"__get_tls_hooks", _hybris_hook_get_tls_hooks}, {"sscanf", sscanf}, {"scanf", scanf}, {"vscanf", vscanf}, @@ -1666,34 +2694,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}, +}; + +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}, }; -void *get_hooked_symbol(char *sym) + +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) { - struct _hook *ptr = &hooks[0]; - static int counter = -1; + 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); - while (ptr->name != NULL) +#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) +{ + static int sorted = 0; + static intptr_t counter = -1; + void *found = NULL; + struct _hook key; + + /* 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(); } diff --git a/hybris/common/hooks_shm.c b/hybris/common/hooks_shm.c index d1d4b3436..c90cee576 100644 --- a/hybris/common/hooks_shm.c +++ b/hybris/common/hooks_shm.c @@ -16,12 +16,13 @@ * */ -#include "hooks_shm.h" +#include "config.h" -#define _GNU_SOURCE +#include "hooks_shm.h" #include #include +#include #include #include #include @@ -37,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 */ @@ -124,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, @@ -162,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(); @@ -172,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; @@ -200,7 +208,7 @@ void *hybris_get_shmpointer(hybris_shm_pointer_t handle) _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* ! @@ -242,7 +250,7 @@ hybris_shm_pointer_t hybris_shm_alloc(size_t size) /* 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; diff --git a/hybris/common/hooks_shm.h b/hybris/common/hooks_shm.h index aabf5cd2a..2f91f66d9 100644 --- a/hybris/common/hooks_shm.h +++ b/hybris/common/hooks_shm.h @@ -19,8 +19,12 @@ #define HOOKS_SHM_H_ #include +#include -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 diff --git a/hybris/common/ics/MODULE_LICENSE_APACHE2 b/hybris/common/ics/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29bb..000000000 diff --git a/hybris/common/ics/Makefile.am b/hybris/common/ics/Makefile.am deleted file mode 100644 index de4bdad87..000000000 --- a/hybris/common/ics/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -if WANT_ARCH_ARM -ARCHFLAGS = -DHAVE_ARM_TLS_REGISTER -DANDROID_ARM_LINKER -endif - -if WANT_ARCH_X86 -ARCHFLAGS = -DANDROID_X86_LINKER -endif - -noinst_LTLIBRARIES = \ - libandroid-linker.la -libandroid_linker_la_SOURCES = \ - dlfcn.c \ - linker.c \ - linker_environ.c \ - linker_format.c \ - rt.c -libandroid_linker_la_CFLAGS = \ - -I$(top_srcdir)/include \ - $(ANDROID_HEADERS_CFLAGS)\ - -I$(top_srcdir)/common \ - -DLINKER_TEXT_BASE=0xB0000100 \ - -DLINKER_AREA_SIZE=0x01000000 \ - $(ARCHFLAGS) - -if WANT_DEBUG -libandroid_linker_la_CFLAGS += -DLINKER_DEBUG=1 -else -libandroid_linker_la_CFLAGS += -DLINKER_DEBUG=0 -endif diff --git a/hybris/common/ics/NOTICE b/hybris/common/ics/NOTICE deleted file mode 100644 index c5b1efa7a..000000000 --- a/hybris/common/ics/NOTICE +++ /dev/null @@ -1,190 +0,0 @@ - - Copyright (c) 2005-2008, 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. - - 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. - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - diff --git a/hybris/common/ics/README.TXT b/hybris/common/ics/README.TXT deleted file mode 100644 index a8efe3508..000000000 --- a/hybris/common/ics/README.TXT +++ /dev/null @@ -1,143 +0,0 @@ -Android Dynamic Linker Design Notes -=================================== - -Introduction: -------------- - -This document provides several notes related to the design of the Android -dynamic linker. - - -Prelinking: ------------ - -System libraries in Android are internally prelinked, which means that -any internal relocations within them are stripped from the corresponding -shared object, in order to reduce size and speed up loading. - -Such libraries can only be loaded at the very specific virtual memory address -they have been prelinked to (during the build process). The list of prelinked -system libraries and their corresponding virtual memory address is found in -the file: - - build/core/prelink-linux-.map - -It should be updated each time a new system library is added to the -system. - -The prelink step happens at build time, and uses the 'soslim' and 'apriori' -tools: - - - 'apriori' is the real prelink tool which removes relocations from the - shared object, however, it must be given a list of symbols to remove - from the file. - - - 'soslim' is used to find symbols in an executable ELF file - and generate a list that can be passed to 'apriori'. - -By default, these tools are only used to remove internal symbols from -libraries, though they have been designed to allow more aggressive -optimizations (e.g. 'global' prelinking and symbol stripping, which -prevent replacing individual system libraries though). - -You can disable prelinking at build time by modifying your Android.mk with -a line like: - - LOCAL_PRELINK_MODULE := false - - -Initialization and Termination functions: ------------------------------------------ - -The Unix Sys V Binary Interface standard states that an -executable can have the following entries in its .dynamic -section: - - DT_INIT - Points to the address of an initialization function - that must be called when the file is loaded. - - DT_INIT_ARRAY - Points to an array of function addresses that must be - called, in-order, to perform initialization. Some of - the entries in the array can be 0 or -1, and should - be ignored. - - Note: this is generally stored in a .init_array section - - DT_INIT_ARRAYSZ - The size of the DT_INITARRAY, if any - - DT_FINI - Points to the address of a finalization function which - must be called when the file is unloaded or the process - terminated. - - DT_FINI_ARRAY - Same as DT_INITARRAY but for finalizers. Note that the - functions must be called in reverse-order though - - Note: this is generally stored in a .fini_array section - - DT_FINI_ARRAYSZ - Size of FT_FINIARRAY - - DT_PREINIT_ARRAY - An array similar to DT_INIT_ARRAY which must *only* be - present in executables, not shared libraries, which contains - a list of functions that need to be called before any other - initialization function (i.e. DT_INIT and/or DT_INIT_ARRAY) - - Note: this is generally stored in a .preinit_array section - - DT_PREINIT_ARRAYSZ - The size of DT_PREINIT_ARRAY - -If both a DT_INIT and DT_INITARRAY entry are present, the DT_INIT -function must be called before the DT_INITARRAY functions. - -Consequently, the DT_FINIARRAY must be parsed in reverse order before -the DT_FINI function, if both are available. - -Note that the implementation of static C++ constructors is very -much processor dependent, and may use different ELF sections. - -On the ARM (see "C++ ABI for ARM" document), the static constructors -must be called explicitly from the DT_INIT_ARRAY, and each one of them -shall register a destructor by calling the special __eabi_atexit() -function (provided by the C library). The DT_FINI_ARRAY is not used -by static C++ destructors. - -On x86, the lists of constructors and destructors are placed in special -sections named ".ctors" and ".dtors", and the DT_INIT / DT_FINI functions -are in charge of calling them explicitly. - - -Debugging: ----------- - -It is possible to enable debug output in the dynamic linker. To do so, -follow these steps: - -1/ Modify the line in Android.mk that says: - - LOCAL_CFLAGS += -DLINKER_DEBUG=0 - - Into the following: - - LOCAL_CFLAGS += -DLINKER_DEBUG=1 - -2/ Force-rebuild the dynamic linker: - - cd bionic/linker - mm -B - -3/ Rebuild a new system image. - -You can increase the verbosity of debug traces by defining the DEBUG -environment variable to a numeric value from 0 to 2. 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 in "linker_debug.h". diff --git a/hybris/common/ics/arch/sh/begin.S b/hybris/common/ics/arch/sh/begin.S deleted file mode 100644 index 6f495578c..000000000 --- a/hybris/common/ics/arch/sh/begin.S +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ -.text -.align 4 -.type _start,#function -.globl _start - -_start: - mov r15, r4 - - mov.l 0f, r0 - jsr @r0 - nop - - /* linker init returns the _entry address in the main image */ - jmp @r0 - nop - - .balign 4 -0: .long __linker_init - - .section .ctors, "wa" - .globl __CTOR_LIST__ -__CTOR_LIST__: - .long -1 diff --git a/hybris/common/ics/debugger.c b/hybris/common/ics/debugger.c deleted file mode 100644 index 648dc78f4..000000000 --- a/hybris/common/ics/debugger.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include - -#include "linker.h" - -#include -#include - -void notify_gdb_of_libraries(); - -#define RETRY_ON_EINTR(ret,cond) \ - do { \ - ret = (cond); \ - } while (ret < 0 && errno == EINTR) - - -static int socket_abstract_client(const char *name, int type) -{ - struct sockaddr_un addr; - size_t namelen; - socklen_t alen; - int s, err; - - namelen = strlen(name); - - // Test with length +1 for the *initial* '\0'. - if ((namelen + 1) > sizeof(addr.sun_path)) { - errno = EINVAL; - return -1; - } - - /* This is used for abstract socket namespace, we need - * an initial '\0' at the start of the Unix socket path. - * - * Note: The path in this case is *not* supposed to be - * '\0'-terminated. ("man 7 unix" for the gory details.) - */ - memset (&addr, 0, sizeof addr); - addr.sun_family = AF_LOCAL; - addr.sun_path[0] = 0; - memcpy(addr.sun_path + 1, name, namelen); - - alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; - - s = socket(AF_LOCAL, type, 0); - if(s < 0) return -1; - - RETRY_ON_EINTR(err,connect(s, (struct sockaddr *) &addr, alen)); - if (err < 0) { - close(s); - s = -1; - } - - return s; -} - -#include "linker_format.h" -#include <../libc/private/logd.h> - -/* - * Writes a summary of the signal to the log file. - * - * We could be here as a result of native heap corruption, or while a - * mutex is being held, so we don't want to use any libc functions that - * could allocate memory or hold a lock. - */ -static void logSignalSummary(int signum, const siginfo_t* info) -{ - char buffer[128]; - - char* signame; - switch (signum) { - case SIGILL: signame = "SIGILL"; break; - case SIGABRT: signame = "SIGABRT"; break; - case SIGBUS: signame = "SIGBUS"; break; - case SIGFPE: signame = "SIGFPE"; break; - case SIGSEGV: signame = "SIGSEGV"; break; - case SIGSTKFLT: signame = "SIGSTKFLT"; break; - case SIGPIPE: signame = "SIGPIPE"; break; - default: signame = "???"; break; - } - - format_buffer(buffer, sizeof(buffer), - "Fatal signal %d (%s) at 0x%08x (code=%d)", - signum, signame, info->si_addr, info->si_code); - - __libc_android_log_write(ANDROID_LOG_FATAL, "libc", buffer); -} - -/* - * Catches fatal signals so we can ask debuggerd to ptrace us before - * we crash. - */ -void debugger_signal_handler(int n, siginfo_t* info, void* unused) -{ - unsigned tid; - int s; - - logSignalSummary(n, info); - - tid = gettid(); - s = socket_abstract_client("android:debuggerd", SOCK_STREAM); - - if(s >= 0) { - /* debugger knows our pid from the credentials on the - * local socket but we need to tell it our tid. It - * is paranoid and will verify that we are giving a tid - * that's actually in our process - */ - int ret; - - RETRY_ON_EINTR(ret, write(s, &tid, sizeof(unsigned))); - if (ret == sizeof(unsigned)) { - /* if the write failed, there is no point to read on - * the file descriptor. */ - RETRY_ON_EINTR(ret, read(s, &tid, 1)); - notify_gdb_of_libraries(); - } - close(s); - } - - /* remove our net so we fault for real when we return */ - signal(n, SIG_DFL); -} - -void debugger_init() -{ - struct sigaction act; - memset(&act, 0, sizeof(act)); - act.sa_sigaction = debugger_signal_handler; - act.sa_flags = SA_RESTART | SA_SIGINFO; - sigemptyset(&act.sa_mask); - - sigaction(SIGILL, &act, NULL); - sigaction(SIGABRT, &act, NULL); - sigaction(SIGBUS, &act, NULL); - sigaction(SIGFPE, &act, NULL); - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGSTKFLT, &act, NULL); - sigaction(SIGPIPE, &act, NULL); -} diff --git a/hybris/common/ics/dlfcn.c b/hybris/common/ics/dlfcn.c deleted file mode 100644 index 27cc109a1..000000000 --- a/hybris/common/ics/dlfcn.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * 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. - */ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include "linker.h" -#include "linker_format.h" - -/* This file hijacks the symbols stubbed out in libdl.so. */ - -#define DL_SUCCESS 0 -#define DL_ERR_CANNOT_LOAD_LIBRARY 1 -#define DL_ERR_INVALID_LIBRARY_HANDLE 2 -#define DL_ERR_BAD_SYMBOL_NAME 3 -#define DL_ERR_SYMBOL_NOT_FOUND 4 -#define DL_ERR_SYMBOL_NOT_GLOBAL 5 - -static char dl_err_buf[1024]; -static const char *dl_err_str; - -static const char *dl_errors[] = { - [DL_ERR_CANNOT_LOAD_LIBRARY] = "Cannot load library", - [DL_ERR_INVALID_LIBRARY_HANDLE] = "Invalid library handle", - [DL_ERR_BAD_SYMBOL_NAME] = "Invalid symbol name", - [DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found", - [DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global", -}; - -#define likely(expr) __builtin_expect (expr, 1) -#define unlikely(expr) __builtin_expect (expr, 0) - -static pthread_mutex_t dl_lock = PTHREAD_MUTEX_INITIALIZER; - -static void set_dlerror(int err) -{ - format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err], - linker_get_error()); - dl_err_str = (const char *)&dl_err_buf[0]; -}; - -void *android_dlopen(const char *filename, int flag) -{ - soinfo *ret; - - pthread_mutex_lock(&dl_lock); - ret = find_library(filename); - if (unlikely(ret == NULL)) { - set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY); - } else { - ret->refcount++; - } - pthread_mutex_unlock(&dl_lock); - return ret; -} - -const char *android_dlerror(void) -{ - const char *tmp = dl_err_str; - dl_err_str = NULL; - return (const char *)tmp; -} - -void *android_dlsym(void *handle, const char *symbol) -{ - soinfo *found; - Elf32_Sym *sym; - unsigned bind; - - pthread_mutex_lock(&dl_lock); - - if(unlikely(handle == 0)) { - set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE); - goto err; - } - if(unlikely(symbol == 0)) { - set_dlerror(DL_ERR_BAD_SYMBOL_NAME); - goto err; - } - - if(handle == RTLD_DEFAULT) { - sym = lookup(symbol, &found, NULL); - } else if(handle == RTLD_NEXT) { - void *ret_addr = __builtin_return_address(0); - soinfo *si = find_containing_library(ret_addr); - - sym = NULL; - if(si && si->next) { - sym = lookup(symbol, &found, si->next); - } - } else { - found = (soinfo*)handle; - sym = lookup_in_library(found, symbol); - } - - if(likely(sym != 0)) { - bind = ELF32_ST_BIND(sym->st_info); - - if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) { - unsigned ret = sym->st_value + found->base; - pthread_mutex_unlock(&dl_lock); - return (void*)ret; - } - - set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL); - } - else - set_dlerror(DL_ERR_SYMBOL_NOT_FOUND); - -err: - pthread_mutex_unlock(&dl_lock); - return 0; -} - -int android_dladdr(const void *addr, Dl_info *info) -{ - int ret = 0; - - pthread_mutex_lock(&dl_lock); - - /* Determine if this address can be found in any library currently mapped */ - soinfo *si = find_containing_library(addr); - - if(si) { - memset(info, 0, sizeof(Dl_info)); - - info->dli_fname = si->name; - 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); - - if(sym != NULL) { - info->dli_sname = si->strtab + sym->st_name; - info->dli_saddr = (void*)(si->base + sym->st_value); - } - - ret = 1; - } - - pthread_mutex_unlock(&dl_lock); - - return ret; -} - -int android_dlclose(void *handle) -{ - pthread_mutex_lock(&dl_lock); - (void)unload_library((soinfo*)handle); - pthread_mutex_unlock(&dl_lock); - return 0; -} - -#if defined(ANDROID_ARM_LINKER) -// 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\0" - -_Unwind_Ptr android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount); - -#elif defined(ANDROID_X86_LINKER) -// 0000000 00011111 111112 22222222 2333333 3333444444444455 -// 0123456 78901234 567890 12345678 9012345 6789012345678901 -#define ANDROID_LIBDL_STRTAB \ - "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0" - -int android_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data),void *data); - -#elif defined(ANDROID_SH_LINKER) -// 0000000 00011111 111112 22222222 2333333 3333444444444455 -// 0123456 78901234 567890 12345678 9012345 6789012345678901 -#define ANDROID_LIBDL_STRTAB \ - "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0" - -#else /* !defined(ANDROID_ARM_LINKER) && !defined(ANDROID_X86_LINKER) */ -#error Unsupported architecture. Only ARM and x86 are presently supported. -#endif - - -static Elf32_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 - // in the strtab with a \0 to make iterating through the symtab easier. - { 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_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 7, - st_value: (Elf32_Addr) &android_dlclose, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 15, - st_value: (Elf32_Addr) &android_dlsym, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 21, - st_value: (Elf32_Addr) &android_dlerror, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, - { st_name: 29, - st_value: (Elf32_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_info: STB_GLOBAL << 4, - st_shndx: 1, - }, -#elif defined(ANDROID_X86_LINKER) - { st_name: 36, - st_value: (Elf32_Addr) &android_dl_iterate_phdr, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, -#elif defined(ANDROID_SH_LINKER) - { st_name: 36, - st_value: (Elf32_Addr) &android_dl_iterate_phdr, - st_info: STB_GLOBAL << 4, - st_shndx: 1, - }, -#endif -}; - -/* Fake out a hash table with a single bucket. - * A search of the hash table will look through - * libdl_symtab starting with index [1], then - * use libdl_chains to find the next index to - * look at. libdl_chains should be set up to - * walk through every element in libdl_symtab, - * and then end with 0 (sentinel value). - * - * I.e., libdl_chains should look like - * { 0, 2, 3, ... N, 0 } where N is the number - * of actual symbols, or nelems(libdl_symtab)-1 - * (since the first element of libdl_symtab is not - * a real symbol). - * - * (see _elf_lookup()) - * - * Note that adding any new symbols here requires - * stubbing them out in libdl. - */ -static unsigned libdl_buckets[1] = { 1 }; -static unsigned libdl_chains[7] = { 0, 2, 3, 4, 5, 6, 0 }; - -soinfo libdl_info = { - name: "libdl.so", - flags: FLAG_LINKED, - - strtab: ANDROID_LIBDL_STRTAB, - symtab: libdl_symtab, - - nbucket: 1, - nchain: 7, - bucket: libdl_buckets, - chain: libdl_chains, -}; - diff --git a/hybris/common/ics/linker.c b/hybris/common/ics/linker.c deleted file mode 100644 index 1425f4328..000000000 --- a/hybris/common/ics/linker.c +++ /dev/null @@ -1,2257 +0,0 @@ -/* - * Copyright (C) 2008, 2009 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 - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -/* special private C library header - see Android.mk */ -#include "bionic_tls.h" - -#include "linker.h" -#include "linker_debug.h" -#include "linker_environ.h" -#include "linker_format.h" - -#define ALLOW_SYMBOLS_FROM_MAIN 1 -#define SO_MAX 128 - -/* Assume average path length of 64 and max 8 paths */ -#define LDPATH_BUFSIZE 512 -#define LDPATH_MAX 8 - -#define LDPRELOAD_BUFSIZE 512 -#define LDPRELOAD_MAX 8 - -/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<< - * - * Do NOT use malloc() and friends or pthread_*() code here. - * Don't use printf() either; it's caused mysterious memory - * corruption in the past. - * The linker runs before we bring up libc and it's easiest - * to make sure it does not depend on any complex libc features - * - * open issues / todo: - * - * - are we doing everything we should for ARM_COPY relocations? - * - cleaner error reporting - * - after linking, set as much stuff as possible to READONLY - * and NOEXEC - * - linker hardcodes PAGE_SIZE and PAGE_MASK because the kernel - * headers provide versions that are negative... - * - allocate space for soinfo structs dynamically instead of - * having a hard limit (64) -*/ - - -static int link_image(soinfo *si, unsigned wr_offset); - -static int socount = 0; -static soinfo sopool[SO_MAX]; -static soinfo *freelist = NULL; -static soinfo *solist = &libdl_info; -static soinfo *sonext = &libdl_info; -#if ALLOW_SYMBOLS_FROM_MAIN -static soinfo *somain; /* main process, always the one after libdl_info */ -#endif - - -static inline int validate_soinfo(soinfo *si) -{ - return (si >= sopool && si < sopool + SO_MAX) || - si == &libdl_info; -} - -static char ldpaths_buf[LDPATH_BUFSIZE]; -static const char *ldpaths[LDPATH_MAX + 1]; - -static char ldpreloads_buf[LDPRELOAD_BUFSIZE]; -static const char *ldpreload_names[LDPRELOAD_MAX + 1]; - -static soinfo *preloads[LDPRELOAD_MAX + 1]; - -#if LINKER_DEBUG -int debug_verbosity; -#endif - -static int pid; - -/* This boolean is set if the program being loaded is setuid */ -static int program_is_setuid; - -#if STATS -struct _link_stats linker_stats; -#endif - -#if COUNT_PAGES -unsigned bitmask[4096]; -#endif - -#ifndef PT_ARM_EXIDX -#define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */ -#endif - -static char tmp_err_buf[768]; -static char __linker_dl_err_buf[768]; -#define DL_ERR(fmt, x...) \ - do { \ - format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf), \ - "%s[%d]: " fmt, __func__, __LINE__, ##x); \ - ERROR(fmt "\n", ##x); \ - } while(0) - -const char *linker_get_error(void) -{ - return (const char *)&__linker_dl_err_buf[0]; -} - -/* - * This function is an empty stub where GDB locates a breakpoint to get notified - * about linker activity. - */ -extern void __attribute__((noinline)) rtld_db_dlactivity(void); - -static struct r_debug _r_debug = {1, NULL, &rtld_db_dlactivity, - RT_CONSISTENT, 0}; -static struct link_map *r_debug_tail = 0; - -static pthread_mutex_t _r_debug_lock = PTHREAD_MUTEX_INITIALIZER; - -static void insert_soinfo_into_debug_map(soinfo * info) -{ - struct link_map * map; - - /* Copy the necessary fields into the debug structure. - */ - map = &(info->linkmap); - map->l_addr = info->base; - map->l_name = (char*) info->name; - map->l_ld = (uintptr_t)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) -{ - struct link_map * map = &(info->linkmap); - - 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; -} - -void notify_gdb_of_load(soinfo * info) -{ - if (info->flags & FLAG_EXE) { - // GDB already knows about the main executable - return; - } - - pthread_mutex_lock(&_r_debug_lock); - - _r_debug.r_state = RT_ADD; - rtld_db_dlactivity(); - - insert_soinfo_into_debug_map(info); - - _r_debug.r_state = RT_CONSISTENT; - rtld_db_dlactivity(); - - pthread_mutex_unlock(&_r_debug_lock); -} - -void notify_gdb_of_unload(soinfo * info) -{ - if (info->flags & FLAG_EXE) { - // GDB already knows about the main executable - return; - } - - pthread_mutex_lock(&_r_debug_lock); - - _r_debug.r_state = RT_DELETE; - rtld_db_dlactivity(); - - remove_soinfo_from_debug_map(info); - - _r_debug.r_state = RT_CONSISTENT; - rtld_db_dlactivity(); - - pthread_mutex_unlock(&_r_debug_lock); -} - -void notify_gdb_of_libraries() -{ - _r_debug.r_state = RT_ADD; - rtld_db_dlactivity(); - _r_debug.r_state = RT_CONSISTENT; - rtld_db_dlactivity(); -} - -static soinfo *alloc_info(const char *name) -{ - soinfo *si; - - if(strlen(name) >= SOINFO_NAME_LEN) { - DL_ERR("%5d library name %s too long", pid, name); - return NULL; - } - - /* The freelist is populated when we call free_info(), which in turn is - done only by dlclose(), which is not likely to be used. - */ - if (!freelist) { - if(socount == SO_MAX) { - DL_ERR("%5d too many libraries when loading %s", pid, name); - return NULL; - } - freelist = sopool + socount++; - freelist->next = NULL; - } - - si = freelist; - freelist = freelist->next; - - /* Make sure we get a clean block of soinfo */ - memset(si, 0, sizeof(soinfo)); - strlcpy((char*) si->name, name, sizeof(si->name)); - sonext->next = si; - si->next = NULL; - si->refcount = 0; - sonext = si; - - TRACE("%5d name %s: allocated soinfo @ %p\n", pid, name, si); - return si; -} - -static void free_info(soinfo *si) -{ - soinfo *prev = NULL, *trav; - - TRACE("%5d name %s: freeing soinfo @ %p\n", pid, si->name, si); - - for(trav = solist; trav != NULL; trav = trav->next){ - if (trav == si) - break; - prev = trav; - } - if (trav == NULL) { - /* si was not ni solist */ - DL_ERR("%5d name %s is not in solist!", pid, si->name); - return; - } - - /* 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->next = freelist; - freelist = si; -} - -const char *addr_to_name(unsigned addr) -{ - soinfo *si; - - for(si = solist; si != 0; si = si->next){ - if((addr >= si->base) && (addr < (si->base + si->size))) { - return si->name; - } - } - - return ""; -} - -/* 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.c and libdl.so. - */ -#ifdef ANDROID_ARM_LINKER -_Unwind_Ptr android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount) -{ - soinfo *si; - unsigned addr = (unsigned)pc; - - for (si = solist; si != 0; si = si->next){ - if ((addr >= si->base) && (addr < (si->base + si->size))) { - *pcount = si->ARM_exidx_count; - return (_Unwind_Ptr)(si->base + (unsigned long)si->ARM_exidx); - } - } - *pcount = 0; - return NULL; -} -#elif defined(ANDROID_X86_LINKER) -/* Here, we only have to provide a callback to iterate across all the - * loaded libraries. gcc_eh does the rest. */ -int -android_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data), - void *data) -{ - soinfo *si; - struct dl_phdr_info dl_info; - int rv = 0; - - for (si = solist; si != NULL; si = si->next) { - dl_info.dlpi_addr = si->linkmap.l_addr; - dl_info.dlpi_name = si->linkmap.l_name; - dl_info.dlpi_phdr = si->phdr; - dl_info.dlpi_phnum = si->phnum; - rv = cb(&dl_info, sizeof (struct dl_phdr_info), data); - if (rv != 0) - break; - } - return rv; -} -#endif - -static Elf32_Sym *_elf_lookup(soinfo *si, unsigned hash, const char *name) -{ - Elf32_Sym *s; - Elf32_Sym *symtab = si->symtab; - const char *strtab = si->strtab; - unsigned n; - - TRACE_TYPE(LOOKUP, "%5d SEARCH %s in %s@0x%08x %08x %d\n", pid, - name, si->name, si->base, hash, hash % si->nbucket); - n = hash % si->nbucket; - - for(n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]){ - s = symtab + n; - if(strcmp(strtab + s->st_name, name)) continue; - - /* only concern ourselves with global and weak symbol definitions */ - switch(ELF32_ST_BIND(s->st_info)){ - case STB_GLOBAL: - case STB_WEAK: - /* no section == undefined */ - if(s->st_shndx == 0) continue; - - TRACE_TYPE(LOOKUP, "%5d FOUND %s in %s (%08x) %d\n", pid, - name, si->name, s->st_value, s->st_size); - return s; - } - } - - return NULL; -} - -static unsigned elfhash(const char *_name) -{ - const unsigned char *name = (const unsigned char *) _name; - unsigned h = 0, g; - - while(*name) { - h = (h << 4) + *name++; - g = h & 0xf0000000; - h ^= g; - h ^= g >> 24; - } - return h; -} - -static Elf32_Sym * -_do_lookup(soinfo *si, const char *name, unsigned *base) -{ - unsigned elf_hash = elfhash(name); - Elf32_Sym *s; - unsigned *d; - soinfo *lsi = si; - int i; - - /* Look for symbols in the local scope first (the object who is - * searching). This happens with C++ templates on i386 for some - * reason. - * - * Notes on weak symbols: - * The ELF specs are ambigious about treatment of weak definitions in - * dynamic linking. Some systems return the first definition found - * and some the first non-weak definition. This is system dependent. - * Here we return the first definition found for simplicity. */ - s = _elf_lookup(si, elf_hash, name); - if(s != NULL) - goto done; - - /* Next, look for it in the preloads list */ - for(i = 0; preloads[i] != NULL; i++) { - lsi = preloads[i]; - s = _elf_lookup(lsi, elf_hash, name); - if(s != NULL) - goto done; - } - - for(d = si->dynamic; *d; d += 2) { - if(d[0] == DT_NEEDED){ - lsi = (soinfo *)d[1]; - if (!validate_soinfo(lsi)) { - DL_ERR("%5d bad DT_NEEDED pointer in %s", - pid, si->name); - return NULL; - } - - DEBUG("%5d %s: looking up %s in %s\n", - pid, si->name, name, lsi->name); - s = _elf_lookup(lsi, elf_hash, name); - if ((s != NULL) && (s->st_shndx != SHN_UNDEF)) - goto done; - } - } - -#if ALLOW_SYMBOLS_FROM_MAIN - /* If we are resolving relocations while dlopen()ing a library, it's OK for - * the library to resolve a symbol that's defined in the executable itself, - * although this is rare and is generally a bad idea. - */ - if (somain) { - lsi = somain; - DEBUG("%5d %s: looking up %s in executable %s\n", - pid, si->name, name, lsi->name); - s = _elf_lookup(lsi, elf_hash, name); - } -#endif - -done: - if(s != NULL) { - TRACE_TYPE(LOOKUP, "%5d si %s sym %s s->st_value = 0x%08x, " - "found in %s, base = 0x%08x\n", - pid, si->name, name, s->st_value, lsi->name, lsi->base); - *base = lsi->base; - return s; - } - - return NULL; -} - -/* 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) -{ - 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) -{ - unsigned elf_hash = elfhash(name); - Elf32_Sym *s = NULL; - soinfo *si; - - if(start == NULL) { - start = solist; - } - - for(si = start; (s == NULL) && (si != NULL); si = si->next) - { - if(si->flags & FLAG_ERROR) - continue; - s = _elf_lookup(si, elf_hash, name); - if (s != NULL) { - *found = si; - break; - } - } - - if(s != NULL) { - TRACE_TYPE(LOOKUP, "%5d %s s->st_value = 0x%08x, " - "si->base = 0x%08x\n", pid, name, s->st_value, si->base); - return s; - } - - return NULL; -} - -soinfo *find_containing_library(const void *addr) -{ - soinfo *si; - - for(si = solist; si != NULL; si = si->next) - { - if((unsigned)addr >= si->base && (unsigned)addr - si->base < si->size) { - return si; - } - } - - return NULL; -} - -Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si) -{ - unsigned int i; - unsigned soaddr = (unsigned)addr - si->base; - - /* Search the library's symbol table for any defined symbol which - * contains this address */ - for(i=0; inchain; i++) { - Elf32_Sym *sym = &si->symtab[i]; - - if(sym->st_shndx != SHN_UNDEF && - soaddr >= sym->st_value && - soaddr < sym->st_value + sym->st_size) { - return sym; - } - } - - return NULL; -} - -#if 0 -static void dump(soinfo *si) -{ - Elf32_Sym *s = si->symtab; - unsigned n; - - for(n = 0; n < si->nchain; n++) { - TRACE("%5d %04d> %08x: %02x %04x %08x %08x %s\n", pid, n, s, - s->st_info, s->st_shndx, s->st_value, s->st_size, - si->strtab + s->st_name); - s++; - } -} -#endif - -static const char *sopaths[] = { - "/vendor/lib", - "/system/lib", - 0 -}; - -static int _open_lib(const char *name) -{ - int fd; - struct stat filestat; - - if ((stat(name, &filestat) >= 0) && S_ISREG(filestat.st_mode)) { - if ((fd = open(name, O_RDONLY)) >= 0) - return fd; - } - - return -1; -} - -static int open_library(const char *name) -{ - int fd; - char buf[512]; - const char **path; - int n; - - TRACE("[ %5d opening %s ]\n", pid, name); - - if(name == 0) return -1; - if(strlen(name) > 256) return -1; - - if ((name[0] == '/') && ((fd = _open_lib(name)) >= 0)) - return fd; - - for (path = ldpaths; *path; path++) { - n = format_buffer(buf, sizeof(buf), "%s/%s", *path, name); - if (n < 0 || n >= (int)sizeof(buf)) { - WARN("Ignoring very long library path: %s/%s\n", *path, name); - continue; - } - if ((fd = _open_lib(buf)) >= 0) - return fd; - } - for (path = sopaths; *path; path++) { - n = format_buffer(buf, sizeof(buf), "%s/%s", *path, name); - if (n < 0 || n >= (int)sizeof(buf)) { - WARN("Ignoring very long library path: %s/%s\n", *path, name); - continue; - } - if ((fd = _open_lib(buf)) >= 0) - return fd; - } - - return -1; -} - -/* temporary space for holding the first page of the shared lib - * which contains the elf header (with the pht). */ -static unsigned char __header[PAGE_SIZE]; - -typedef struct { - long mmap_addr; - char tag[4]; /* 'P', 'R', 'E', ' ' */ -} prelink_info_t; - -/* Returns the requested base address if the library is prelinked, - * and 0 otherwise. */ -static unsigned long -is_prelinked(int fd, const char *name) -{ - off_t sz; - prelink_info_t info; - - sz = lseek(fd, -sizeof(prelink_info_t), SEEK_END); - if (sz < 0) { - DL_ERR("lseek() failed!"); - return 0; - } - - if (read(fd, &info, sizeof(info)) != sizeof(info)) { - WARN("Could not read prelink_info_t structure for `%s`\n", name); - return 0; - } - - if (strncmp(info.tag, "PRE ", 4)) { - WARN("`%s` is not a prelinked library\n", name); - return 0; - } - - return (unsigned long)info.mmap_addr; -} - -/* verify_elf_object - * Verifies if the object @ base is a valid ELF object - * - * Args: - * - * Returns: - * 0 on success - * -1 if no valid ELF object is found @ base. - */ -static int -verify_elf_object(void *base, const char *name) -{ - Elf32_Ehdr *hdr = (Elf32_Ehdr *) base; - - if (hdr->e_ident[EI_MAG0] != ELFMAG0) return -1; - if (hdr->e_ident[EI_MAG1] != ELFMAG1) return -1; - if (hdr->e_ident[EI_MAG2] != ELFMAG2) return -1; - if (hdr->e_ident[EI_MAG3] != ELFMAG3) return -1; - - /* TODO: Should we verify anything else in the header? */ -#ifdef ANDROID_ARM_LINKER - if (hdr->e_machine != EM_ARM) return -1; -#elif defined(ANDROID_X86_LINKER) - if (hdr->e_machine != EM_386) return -1; -#endif - return 0; -} - - -/* get_lib_extents - * Retrieves the base (*base) address where the ELF object should be - * mapped and its overall memory size (*total_sz). - * - * Args: - * fd: Opened file descriptor for the library - * name: The name of the library - * _hdr: Pointer to the header page of the library - * total_sz: Total size of the memory that should be allocated for - * this library - * - * Returns: - * -1 if there was an error while trying to get the lib extents. - * The possible reasons are: - * - Could not determine if the library was prelinked. - * - The library provided is not a valid ELF object - * 0 if the library did not request a specific base offset (normal - * for non-prelinked libs) - * > 0 if the library requests a specific address to be mapped to. - * This indicates a pre-linked library. - */ -static unsigned -get_lib_extents(int fd, const char *name, void *__hdr, unsigned *total_sz) -{ - unsigned req_base; - unsigned min_vaddr = 0xffffffff; - unsigned max_vaddr = 0; - unsigned char *_hdr = (unsigned char *)__hdr; - Elf32_Ehdr *ehdr = (Elf32_Ehdr *)_hdr; - Elf32_Phdr *phdr; - int cnt; - - TRACE("[ %5d Computing extents for '%s'. ]\n", pid, name); - if (verify_elf_object(_hdr, name) < 0) { - DL_ERR("%5d - %s is not a valid ELF object", pid, name); - return (unsigned)-1; - } - - req_base = (unsigned) is_prelinked(fd, name); - if (req_base == (unsigned)-1) - return -1; - else if (req_base != 0) { - TRACE("[ %5d - Prelinked library '%s' requesting base @ 0x%08x ]\n", - pid, name, req_base); - } else { - TRACE("[ %5d - Non-prelinked library '%s' found. ]\n", pid, name); - } - - phdr = (Elf32_Phdr *)(_hdr + ehdr->e_phoff); - - /* find the min/max p_vaddrs from all the PT_LOAD segments so we can - * get the range. */ - for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) { - if (phdr->p_type == PT_LOAD) { - if ((phdr->p_vaddr + phdr->p_memsz) > max_vaddr) - max_vaddr = phdr->p_vaddr + phdr->p_memsz; - if (phdr->p_vaddr < min_vaddr) - min_vaddr = phdr->p_vaddr; - } - } - - if ((min_vaddr == 0xffffffff) && (max_vaddr == 0)) { - DL_ERR("%5d - No loadable segments found in %s.", pid, name); - return (unsigned)-1; - } - - /* truncate min_vaddr down to page boundary */ - min_vaddr &= ~PAGE_MASK; - - /* round max_vaddr up to the next page */ - max_vaddr = (max_vaddr + PAGE_SIZE - 1) & ~PAGE_MASK; - - *total_sz = (max_vaddr - min_vaddr); - return (unsigned)req_base; -} - -/* alloc_mem_region - * - * This function reserves a chunk of memory to be used for mapping in - * the shared library. We reserve the entire memory region here, and - * then the rest of the linker will relocate the individual loadable - * segments into the correct locations within this memory range. - * - * Args: - * si->base: The requested base of the allocation. If 0, a sane one will be - * chosen in the range LIBBASE <= base < LIBLAST. - * si->size: The size of the allocation. - * - * Returns: - * -1 on failure, and 0 on success. On success, si->base will contain - * the virtual address at which the library will be mapped. - */ - -static int reserve_mem_region(soinfo *si) -{ - void *base = mmap((void *)si->base, si->size, PROT_READ | PROT_EXEC, - MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (base == MAP_FAILED) { - DL_ERR("%5d can NOT map (%sprelinked) library '%s' at 0x%08x " - "as requested, will try general pool: %d (%s)", - pid, (si->base ? "" : "non-"), si->name, si->base, - errno, strerror(errno)); - return -1; - } else if (base != (void *)si->base) { - DL_ERR("OOPS: %5d %sprelinked library '%s' mapped at 0x%08x, " - "not at 0x%08x", pid, (si->base ? "" : "non-"), - si->name, (unsigned)base, si->base); - munmap(base, si->size); - return -1; - } - return 0; -} - -static int -alloc_mem_region(soinfo *si) -{ - if (si->base) { - /* Attempt to mmap a prelinked library. */ - return reserve_mem_region(si); - } - - /* This is not a prelinked library, so we use the kernel's default - allocator. - */ - - void *base = mmap(NULL, si->size, PROT_READ | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (base == MAP_FAILED) { - DL_ERR("%5d mmap of library '%s' failed: %d (%s)\n", - pid, si->name, - errno, strerror(errno)); - goto err; - } - si->base = (unsigned) base; - PRINT("%5d mapped library '%s' to %08x via kernel allocator.\n", - pid, si->name, si->base); - return 0; - -err: - DL_ERR("OOPS: %5d cannot map library '%s'. no vspace available.", - pid, si->name); - return -1; -} - -#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)) -/* load_segments - * - * This function loads all the loadable (PT_LOAD) segments into memory - * at their appropriate memory offsets off the base address. - * - * Args: - * fd: Open file descriptor to the library to load. - * header: Pointer to a header page that contains the ELF header. - * This is needed since we haven't mapped in the real file yet. - * si: ptr to soinfo struct describing the shared object. - * - * Returns: - * 0 on success, -1 on failure. - */ -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); - unsigned char *base = (Elf32_Addr) si->base; - int cnt; - unsigned len; - unsigned char *tmp; - unsigned char *pbase; - unsigned char *extra_base; - unsigned extra_len; - unsigned total_sz = 0; - - si->wrprotect_start = 0xffffffff; - si->wrprotect_end = 0; - - TRACE("[ %5d - Begin loading segments for '%s' @ 0x%08x ]\n", - pid, si->name, (unsigned)si->base); - /* Now go through all the PT_LOAD segments and map them into memory - * at the appropriate locations. */ - for (cnt = 0; cnt < ehdr->e_phnum; ++cnt, ++phdr) { - if (phdr->p_type == PT_LOAD) { - DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid); - /* we want to map in the segment on a page boundary */ - tmp = base + (phdr->p_vaddr & (~PAGE_MASK)); - /* add the # of bytes we masked off above to the total length. */ - len = phdr->p_filesz + (phdr->p_vaddr & PAGE_MASK); - - TRACE("[ %d - Trying to load segment from '%s' @ 0x%08x " - "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x ]\n", pid, si->name, - (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset); - pbase = mmap(tmp, len, PFLAGS_TO_PROT(phdr->p_flags), - MAP_PRIVATE | MAP_FIXED, fd, - phdr->p_offset & (~PAGE_MASK)); - if (pbase == MAP_FAILED) { - DL_ERR("%d failed to map segment from '%s' @ 0x%08x (0x%08x). " - "p_vaddr=0x%08x p_offset=0x%08x", pid, si->name, - (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset); - goto fail; - } - - /* If 'len' didn't end on page boundary, and it's a writable - * segment, zero-fill the rest. */ - if ((len & PAGE_MASK) && (phdr->p_flags & PF_W)) - memset((void *)(pbase + len), 0, PAGE_SIZE - (len & PAGE_MASK)); - - /* Check to see if we need to extend the map for this segment to - * cover the diff between filesz and memsz (i.e. for bss). - * - * base _+---------------------+ page boundary - * . . - * | | - * . . - * pbase _+---------------------+ page boundary - * | | - * . . - * base + p_vaddr _| | - * . \ \ . - * . | filesz | . - * pbase + len _| / | | - * <0 pad> . . . - * extra_base _+------------|--------+ page boundary - * / . . . - * | . . . - * | +------------|--------+ page boundary - * extra_len-> | | | | - * | . | memsz . - * | . | . - * \ _| / | - * . . - * | | - * _+---------------------+ page boundary - */ - tmp = (Elf32_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; - TRACE("[ %5d - Need to extend segment from '%s' @ 0x%08x " - "(0x%08x) ]\n", pid, si->name, (unsigned)tmp, extra_len); - /* map in the extra page(s) as anonymous into the range. - * This is probably not necessary as we already mapped in - * the entire region previously, but we just want to be - * sure. This will also set the right flags on the region - * (though we can probably accomplish the same thing with - * mprotect). - */ - extra_base = mmap((void *)tmp, extra_len, - PFLAGS_TO_PROT(phdr->p_flags), - MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, - -1, 0); - if (extra_base == MAP_FAILED) { - DL_ERR("[ %5d - failed to extend segment from '%s' @ 0x%08x" - " (0x%08x) ]", pid, si->name, (unsigned)tmp, - extra_len); - goto fail; - } - /* TODO: Check if we need to memset-0 this region. - * Anonymous mappings are zero-filled copy-on-writes, so we - * shouldn't need to. */ - TRACE("[ %5d - Segment from '%s' extended @ 0x%08x " - "(0x%08x)\n", pid, si->name, (unsigned)extra_base, - extra_len); - } - /* set the len here to show the full extent of the segment we - * just loaded, mostly for debugging */ - len = (((unsigned)base + phdr->p_vaddr + phdr->p_memsz + - PAGE_SIZE - 1) & (~PAGE_MASK)) - (unsigned)pbase; - TRACE("[ %5d - Successfully loaded segment from '%s' @ 0x%08x " - "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x\n", pid, si->name, - (unsigned)pbase, len, phdr->p_vaddr, phdr->p_offset); - total_sz += len; - /* Make the section writable just in case we'll have to write to - * it during relocation (i.e. text segment). However, we will - * remember what range of addresses should be write protected. - * - */ - if (!(phdr->p_flags & PF_W)) { - if ((unsigned)pbase < si->wrprotect_start) - si->wrprotect_start = (unsigned)pbase; - if (((unsigned)pbase + len) > si->wrprotect_end) - si->wrprotect_end = (unsigned)pbase + len; - mprotect(pbase, len, - PFLAGS_TO_PROT(phdr->p_flags) | PROT_WRITE); - } - } else if (phdr->p_type == PT_DYNAMIC) { - DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid); - /* this segment contains the dynamic linking information */ - si->dynamic = (unsigned *)(base + phdr->p_vaddr); - } else { -#ifdef ANDROID_ARM_LINKER - if (phdr->p_type == PT_ARM_EXIDX) { - DEBUG_DUMP_PHDR(phdr, "PT_ARM_EXIDX", pid); - /* exidx entries (used for stack unwinding) are 8 bytes each. - */ - si->ARM_exidx = (unsigned *)phdr->p_vaddr; - si->ARM_exidx_count = phdr->p_memsz / 8; - } -#endif - } - - } - - /* Sanity check */ - if (total_sz > si->size) { - DL_ERR("%5d - Total length (0x%08x) of mapped segments from '%s' is " - "greater than what was allocated (0x%08x). THIS IS BAD!", - pid, total_sz, si->name, si->size); - goto fail; - } - - TRACE("[ %5d - Finish loading segments for '%s' @ 0x%08x. " - "Total memory footprint: 0x%08x bytes ]\n", pid, si->name, - (unsigned)si->base, si->size); - return 0; - -fail: - /* We can just blindly unmap the entire region even though some things - * were mapped in originally with anonymous and others could have been - * been mapped in from the file before we failed. The kernel will unmap - * all the pages in the range, irrespective of how they got there. - */ - munmap((void *)si->base, si->size); - si->flags |= FLAG_ERROR; - return -1; -} - -/* TODO: Implement this to take care of the fact that Android ARM - * ELF objects shove everything into a single loadable segment that has the - * write bit set. wr_offset is then used to set non-(data|bss) pages to be - * non-writable. - */ -#if 0 -static unsigned -get_wr_offset(int fd, const char *name, Elf32_Ehdr *ehdr) -{ - Elf32_Shdr *shdr_start; - Elf32_Shdr *shdr; - int shdr_sz = ehdr->e_shnum * sizeof(Elf32_Shdr); - int cnt; - unsigned wr_offset = 0xffffffff; - - shdr_start = mmap(0, shdr_sz, PROT_READ, MAP_PRIVATE, fd, - ehdr->e_shoff & (~PAGE_MASK)); - if (shdr_start == MAP_FAILED) { - WARN("%5d - Could not read section header info from '%s'. Will not " - "not be able to determine write-protect offset.\n", pid, name); - return (unsigned)-1; - } - - for(cnt = 0, shdr = shdr_start; cnt < ehdr->e_shnum; ++cnt, ++shdr) { - if ((shdr->sh_type != SHT_NULL) && (shdr->sh_flags & SHF_WRITE) && - (shdr->sh_addr < wr_offset)) { - wr_offset = shdr->sh_addr; - } - } - - munmap(shdr_start, shdr_sz); - return wr_offset; -} -#endif - -static soinfo * -load_library(const char *name) -{ - int fd = open_library(name); - int cnt; - unsigned ext_sz; - unsigned req_base; - const char *bname; - soinfo *si = NULL; - Elf32_Ehdr *hdr; - - if(fd == -1) { - DL_ERR("Library '%s' not found", name); - return NULL; - } - - /* We have to read the ELF header to figure out what to do with this image - */ - if (lseek(fd, 0, SEEK_SET) < 0) { - DL_ERR("lseek() failed!"); - goto fail; - } - - if ((cnt = read(fd, &__header[0], PAGE_SIZE)) < 0) { - DL_ERR("read() failed!"); - goto fail; - } - - /* Parse the ELF header and get the size of the memory footprint for - * the library */ - req_base = get_lib_extents(fd, name, &__header[0], &ext_sz); - if (req_base == (unsigned)-1) - goto fail; - TRACE("[ %5d - '%s' (%s) wants base=0x%08x sz=0x%08x ]\n", pid, name, - (req_base ? "prelinked" : "not pre-linked"), req_base, ext_sz); - - /* Now configure the soinfo struct where we'll store all of our data - * for the ELF object. If the loading fails, we waste the entry, but - * same thing would happen if we failed during linking. Configuring the - * soinfo struct here is a lot more convenient. - */ - bname = strrchr(name, '/'); - si = alloc_info(bname ? bname + 1 : name); - if (si == NULL) - goto fail; - - /* Carve out a chunk of memory where we will map in the individual - * segments */ - si->base = req_base; - si->size = ext_sz; - si->flags = 0; - si->entry = 0; - si->dynamic = (unsigned *)-1; - if (alloc_mem_region(si) < 0) - goto fail; - - TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n", - pid, name, (void *)si->base, (unsigned) ext_sz); - - /* Now actually load the library's segments into right places in memory */ - if (load_segments(fd, &__header[0], si) < 0) { - goto fail; - } - - /* 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); - si->phnum = hdr->e_phnum; - /**/ - - close(fd); - return si; - -fail: - if (si) free_info(si); - close(fd); - return NULL; -} - -static soinfo * -init_library(soinfo *si) -{ - unsigned wr_offset = 0xffffffff; - - /* At this point we know that whatever is loaded @ base is a valid ELF - * shared library whose segments are properly mapped in. */ - TRACE("[ %5d init_library base=0x%08x sz=0x%08x name='%s') ]\n", - pid, si->base, si->size, si->name); - - if(link_image(si, wr_offset)) { - /* We failed to link. However, we can only restore libbase - ** if no additional libraries have moved it since we updated it. - */ - munmap((void *)si->base, si->size); - return NULL; - } - - return si; -} - -soinfo *find_library(const char *name) -{ - soinfo *si; - const char *bname; - -#if ALLOW_SYMBOLS_FROM_MAIN - if (name == NULL) - return somain; -#else - if (name == NULL) - return NULL; -#endif - - bname = strrchr(name, '/'); - bname = bname ? bname + 1 : name; - - for(si = solist; si != 0; si = si->next){ - if(!strcmp(bname, si->name)) { - if(si->flags & FLAG_ERROR) { - DL_ERR("%5d '%s' failed to load previously", pid, bname); - return NULL; - } - if(si->flags & FLAG_LINKED) return si; - DL_ERR("OOPS: %5d recursive link to '%s'", pid, si->name); - return NULL; - } - } - - TRACE("[ %5d '%s' has not been loaded yet. Locating...]\n", pid, name); - si = load_library(name); - if(si == NULL) - return NULL; - return init_library(si); -} - -/* TODO: - * notify gdb of unload - * for non-prelinked libraries, find a way to decrement libbase - */ -static void call_destructors(soinfo *si); -unsigned unload_library(soinfo *si) -{ - unsigned *d; - if (si->refcount == 1) { - TRACE("%5d unloading '%s'\n", pid, si->name); - call_destructors(si); - - - for(d = si->dynamic; *d; d += 2) { - if(d[0] == DT_NEEDED){ - soinfo *lsi = (soinfo *)d[1]; - d[1] = 0; - if (validate_soinfo(lsi)) { - TRACE("%5d %s needs to unload %s\n", pid, - si->name, lsi->name); - unload_library(lsi); - } - else - DL_ERR("%5d %s: could not unload dependent library", - pid, si->name); - } - } - - munmap((char *)si->base, si->size); - notify_gdb_of_unload(si); - free_info(si); - si->refcount = 0; - } - else { - si->refcount--; - PRINT("%5d not unloading '%s', decrementing refcount to %d\n", - pid, si->name, si->refcount); - } - return si->refcount; -} - -/* 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 - * long. - */ -static int reloc_library(soinfo *si, Elf32_Rel *rel, unsigned count) -{ - Elf32_Sym *symtab = si->symtab; - const char *strtab = si->strtab; - Elf32_Sym *s; - unsigned base; - Elf32_Rel *start = rel; - unsigned idx; - - for (idx = 0; idx < count; ++idx) { - unsigned type = ELF32_R_TYPE(rel->r_info); - unsigned sym = ELF32_R_SYM(rel->r_info); - unsigned reloc = (unsigned)(rel->r_offset + si->base); - unsigned sym_addr = 0; - char *sym_name = NULL; - - //printf("%5d Processing '%s' relocation at index %d\n", pid, - // si->name, idx); - if(sym != 0) { - sym_name = (char *)(strtab + symtab[sym].st_name); - //printf("Sym name =%s\n",sym_name); - sym_addr = NULL; - if ((sym_addr = get_hooked_symbol(sym_name)) != NULL) { - //printf("hooked symbol %s to %x\n", sym_name, sym_addr); - } - else - { - s = _do_lookup(si, sym_name, &base); - } - if(sym_addr != NULL) - { - } else - if(s == NULL) { - /* We only allow an undefined symbol if this is a weak - reference.. */ - s = &symtab[sym]; - if (ELF32_ST_BIND(s->st_info) != STB_WEAK) { - DL_ERR("%5d cannot locate '%s'...\n", pid, sym_name); - return -1; - } - - /* 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 nominial base address if the relocation - type is base-relative. - */ - - switch (type) { -#if defined(ANDROID_ARM_LINKER) - case R_ARM_JUMP_SLOT: - case R_ARM_GLOB_DAT: - case R_ARM_ABS32: - case R_ARM_RELATIVE: /* Don't care. */ - case R_ARM_NONE: /* Don't care. */ -#elif defined(ANDROID_X86_LINKER) - case R_386_JUMP_SLOT: - case R_386_GLOB_DAT: - case R_386_32: - case R_386_RELATIVE: /* Dont' care. */ -#endif /* ANDROID_*_LINKER */ - /* sym_addr was initialized to be zero above or relocation - code below does not care about value of sym_addr. - No need to do anything. */ - break; - -#if defined(ANDROID_X86_LINKER) - case R_386_PC32: - sym_addr = reloc; - break; -#endif /* ANDROID_X86_LINKER */ - -#if defined(ANDROID_ARM_LINKER) - case R_ARM_COPY: - /* Fall through. Can't really copy if weak symbol is - not found in run-time. */ -#endif /* ANDROID_ARM_LINKER */ - default: - DL_ERR("%5d unknown weak reloc type %d @ %p (%d)\n", - pid, type, rel, (int) (rel - start)); - return -1; - } - } else { - /* We got a definition. */ -#if 0 - if((base == 0) && (si->base != 0)){ - /* linking from libraries to main image is bad */ - DL_ERR("%5d cannot locate '%s'...", - pid, strtab + symtab[sym].st_name); - return -1; - } -#endif - sym_addr = (unsigned)(s->st_value + base); - } - COUNT_RELOC(RELOC_SYMBOL); - } else { - s = NULL; - } - -/* TODO: This is ugly. Split up the relocations by arch into - * different files. - */ - switch(type){ -#if defined(ANDROID_ARM_LINKER) - case R_ARM_JUMP_SLOT: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) = sym_addr; - break; - case R_ARM_GLOB_DAT: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) = sym_addr; - break; - case R_ARM_ABS32: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO ABS %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) += sym_addr; - break; - case R_ARM_REL32: - COUNT_RELOC(RELOC_RELATIVE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO REL32 %08x <- %08x - %08x %s\n", pid, - reloc, sym_addr, rel->r_offset, sym_name); - *((unsigned*)reloc) += sym_addr - rel->r_offset; - break; -#elif defined(ANDROID_X86_LINKER) - case R_386_JUMP_SLOT: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) = sym_addr; - break; - case R_386_GLOB_DAT: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) = sym_addr; - break; -#endif /* ANDROID_*_LINKER */ - -#if defined(ANDROID_ARM_LINKER) - case R_ARM_RELATIVE: -#elif defined(ANDROID_X86_LINKER) - case R_386_RELATIVE: -#endif /* ANDROID_*_LINKER */ - COUNT_RELOC(RELOC_RELATIVE); - MARK(rel->r_offset); - if(sym){ - DL_ERR("%5d odd RELATIVE form...", pid); - return -1; - } - TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid, - reloc, si->base); - *((unsigned*)reloc) += si->base; - break; - -#if defined(ANDROID_X86_LINKER) - case R_386_32: - COUNT_RELOC(RELOC_RELATIVE); - MARK(rel->r_offset); - - TRACE_TYPE(RELO, "%5d RELO R_386_32 %08x <- +%08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned *)reloc) += (unsigned)sym_addr; - break; - - case R_386_PC32: - COUNT_RELOC(RELOC_RELATIVE); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO R_386_PC32 %08x <- " - "+%08x (%08x - %08x) %s\n", pid, reloc, - (sym_addr - reloc), sym_addr, reloc, sym_name); - *((unsigned *)reloc) += (unsigned)(sym_addr - reloc); - break; -#endif /* ANDROID_X86_LINKER */ - -#ifdef ANDROID_ARM_LINKER - case R_ARM_COPY: - COUNT_RELOC(RELOC_COPY); - MARK(rel->r_offset); - TRACE_TYPE(RELO, "%5d RELO %08x <- %d @ %08x %s\n", pid, - reloc, s->st_size, sym_addr, sym_name); - memcpy((void*)reloc, (void*)sym_addr, s->st_size); - break; - case R_ARM_NONE: - break; -#endif /* ANDROID_ARM_LINKER */ - - default: - DL_ERR("%5d unknown reloc type %d @ %p (%d)", - pid, type, rel, (int) (rel - start)); - return -1; - } - rel++; - } - return 0; -} - -#if defined(ANDROID_SH_LINKER) -static int reloc_library_a(soinfo *si, Elf32_Rela *rela, unsigned count) -{ - Elf32_Sym *symtab = si->symtab; - const char *strtab = si->strtab; - Elf32_Sym *s; - unsigned base; - Elf32_Rela *start = rela; - unsigned idx; - - for (idx = 0; idx < count; ++idx) { - unsigned type = ELF32_R_TYPE(rela->r_info); - unsigned sym = ELF32_R_SYM(rela->r_info); - unsigned reloc = (unsigned)(rela->r_offset + si->base); - unsigned sym_addr = 0; - char *sym_name = NULL; - - DEBUG("%5d Processing '%s' relocation at index %d\n", pid, - si->name, idx); - if(sym != 0) { - sym_name = (char *)(strtab + symtab[sym].st_name); - s = _do_lookup(si, sym_name, &base); - if(s == 0) { - DL_ERR("%5d cannot locate '%s'...", pid, sym_name); - return -1; - } -#if 0 - if((base == 0) && (si->base != 0)){ - /* linking from libraries to main image is bad */ - DL_ERR("%5d cannot locate '%s'...", - pid, strtab + symtab[sym].st_name); - return -1; - } -#endif - if ((s->st_shndx == SHN_UNDEF) && (s->st_value != 0)) { - DL_ERR("%5d In '%s', shndx=%d && value=0x%08x. We do not " - "handle this yet", pid, si->name, s->st_shndx, - s->st_value); - return -1; - } - sym_addr = (unsigned)(s->st_value + base); - COUNT_RELOC(RELOC_SYMBOL); - } else { - s = 0; - } - -/* TODO: This is ugly. Split up the relocations by arch into - * different files. - */ - switch(type){ - case R_SH_JUMP_SLOT: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rela->r_offset); - TRACE_TYPE(RELO, "%5d RELO JMP_SLOT %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) = sym_addr; - break; - case R_SH_GLOB_DAT: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rela->r_offset); - TRACE_TYPE(RELO, "%5d RELO GLOB_DAT %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) = sym_addr; - break; - case R_SH_DIR32: - COUNT_RELOC(RELOC_ABSOLUTE); - MARK(rela->r_offset); - TRACE_TYPE(RELO, "%5d RELO DIR32 %08x <- %08x %s\n", pid, - reloc, sym_addr, sym_name); - *((unsigned*)reloc) += sym_addr; - break; - case R_SH_RELATIVE: - COUNT_RELOC(RELOC_RELATIVE); - MARK(rela->r_offset); - if(sym){ - DL_ERR("%5d odd RELATIVE form...", pid); - return -1; - } - TRACE_TYPE(RELO, "%5d RELO RELATIVE %08x <- +%08x\n", pid, - reloc, si->base); - *((unsigned*)reloc) += si->base; - break; - - default: - DL_ERR("%5d unknown reloc type %d @ %p (%d)", - pid, type, rela, (int) (rela - start)); - return -1; - } - rela++; - } - return 0; -} -#endif /* ANDROID_SH_LINKER */ - - -/* Please read the "Initialization and Termination functions" functions. - * of the linker design note in bionic/linker/README.TXT to understand - * what the following code is doing. - * - * The important things to remember are: - * - * DT_PREINIT_ARRAY must be called first for executables, and should - * not appear in shared libraries. - * - * DT_INIT should be called before DT_INIT_ARRAY if both are present - * - * DT_FINI should be called after DT_FINI_ARRAY if both are present - * - * DT_FINI_ARRAY must be parsed in reverse order. - */ - -static void call_array(unsigned *ctor, int count, int reverse) -{ - int n, inc = 1; - - if (reverse) { - ctor += (count-1); - inc = -1; - } - - for(n = count; n > 0; n--) { - TRACE("[ %5d Looking at %s *0x%08x == 0x%08x ]\n", pid, - reverse ? "dtor" : "ctor", - (unsigned)ctor, (unsigned)*ctor); - void (*func)() = (void (*)()) *ctor; - ctor += inc; - if(((int) func == 0) || ((int) func == -1)) continue; - TRACE("[ %5d Calling func @ 0x%08x ]\n", pid, (unsigned)func); - func(); - } -} - -static void call_constructors(soinfo *si) -{ -#if 0 - if (strcmp(si->name,"libc.so") == 0) { - printf("=============> Skipping libc.so\n"); - return; - } -#endif - - if (si->flags & FLAG_EXE) { - TRACE("[ %5d Calling preinit_array @ 0x%08x [%d] for '%s' ]\n", - pid, (unsigned)si->preinit_array, si->preinit_array_count, - si->name); - call_array(si->preinit_array, si->preinit_array_count, 0); - TRACE("[ %5d Done calling preinit_array for '%s' ]\n", pid, si->name); - } else { - if (si->preinit_array) { - DL_ERR("%5d Shared library '%s' has a preinit_array table @ 0x%08x." - " This is INVALID.", pid, si->name, - (unsigned)si->preinit_array); - } - } - - if (si->init_func) { - TRACE("[ %5d Calling init_func @ 0x%08x for '%s' ]\n", pid, - (unsigned)si->init_func, si->name); - si->init_func(); - TRACE("[ %5d Done calling init_func for '%s' ]\n", pid, si->name); - } - - if (si->init_array) { - TRACE("[ %5d Calling init_array @ 0x%08x [%d] for '%s' ]\n", pid, - (unsigned)si->init_array, si->init_array_count, si->name); - call_array(si->init_array, si->init_array_count, 0); - TRACE("[ %5d Done calling init_array for '%s' ]\n", pid, si->name); - } -} - - -static void call_destructors(soinfo *si) -{ - if (si->fini_array) { - TRACE("[ %5d Calling fini_array @ 0x%08x [%d] for '%s' ]\n", pid, - (unsigned)si->fini_array, si->fini_array_count, si->name); - call_array(si->fini_array, si->fini_array_count, 1); - TRACE("[ %5d Done calling fini_array for '%s' ]\n", pid, si->name); - } - - if (si->fini_func) { - TRACE("[ %5d Calling fini_func @ 0x%08x for '%s' ]\n", pid, - (unsigned)si->fini_func, si->name); - si->fini_func(); - TRACE("[ %5d Done calling fini_func for '%s' ]\n", pid, si->name); - } -} - -/* Force any of the closed stdin, stdout and stderr to be associated with - /dev/null. */ -static int nullify_closed_stdio (void) -{ - int dev_null, i, status; - int return_value = 0; - - dev_null = open("/dev/null", O_RDWR); - if (dev_null < 0) { - DL_ERR("Cannot open /dev/null."); - return -1; - } - TRACE("[ %5d Opened /dev/null file-descriptor=%d]\n", pid, dev_null); - - /* If any of the stdio file descriptors is valid and not associated - with /dev/null, dup /dev/null to it. */ - for (i = 0; i < 3; i++) { - /* If it is /dev/null already, we are done. */ - if (i == dev_null) - continue; - - TRACE("[ %5d Nullifying stdio file descriptor %d]\n", pid, i); - /* The man page of fcntl does not say that fcntl(..,F_GETFL) - can be interrupted but we do this just to be safe. */ - do { - status = fcntl(i, F_GETFL); - } while (status < 0 && errno == EINTR); - - /* If file is openned, we are good. */ - if (status >= 0) - continue; - - /* The only error we allow is that the file descriptor does not - exist, in which case we dup /dev/null to it. */ - if (errno != EBADF) { - DL_ERR("nullify_stdio: unhandled error %s", strerror(errno)); - return_value = -1; - continue; - } - - /* Try dupping /dev/null to this stdio file descriptor and - repeat if there is a signal. Note that any errors in closing - the stdio descriptor are lost. */ - do { - status = dup2(dev_null, i); - } while (status < 0 && errno == EINTR); - - if (status < 0) { - DL_ERR("nullify_stdio: dup2 error %s", strerror(errno)); - return_value = -1; - continue; - } - } - - /* If /dev/null is not one of the stdio file descriptors, close it. */ - if (dev_null > 2) { - TRACE("[ %5d Closing /dev/null file-descriptor=%d]\n", pid, dev_null); - do { - status = close(dev_null); - } while (status < 0 && errno == EINTR); - - if (status < 0) { - DL_ERR("nullify_stdio: close error %s", strerror(errno)); - return_value = -1; - } - } - - return return_value; -} - -static int link_image(soinfo *si, unsigned wr_offset) -{ - unsigned *d; - Elf32_Phdr *phdr = si->phdr; - int phnum = si->phnum; - - INFO("[ %5d linking %s ]\n", pid, si->name); - DEBUG("%5d si->base = 0x%08x si->flags = 0x%08x\n", pid, - si->base, si->flags); - - if (si->flags & FLAG_EXE) { - /* Locate the needed program segments (DYNAMIC/ARM_EXIDX) for - * linkage info if this is the executable. If this was a - * dynamic lib, that would have been done at load time. - * - * TODO: It's unfortunate that small pieces of this are - * repeated from the load_library routine. Refactor this just - * slightly to reuse these bits. - */ - si->size = 0; - for(; phnum > 0; --phnum, ++phdr) { -#ifdef ANDROID_ARM_LINKER - if(phdr->p_type == PT_ARM_EXIDX) { - /* exidx entries (used for stack unwinding) are 8 bytes each. - */ - si->ARM_exidx = (unsigned *)phdr->p_vaddr; - si->ARM_exidx_count = phdr->p_memsz / 8; - } -#endif - if (phdr->p_type == PT_LOAD) { - /* For the executable, we use the si->size field only in - dl_unwind_find_exidx(), so the meaning of si->size - is not the size of the executable; it is the last - virtual address of the loadable part of the executable; - since si->base == 0 for an executable, we use the - range [0, si->size) to determine whether a PC value - falls within the executable section. Of course, if - a value is below phdr->p_vaddr, it's not in the - executable section, but a) we shouldn't be asking for - such a value anyway, and b) if we have to provide - an EXIDX for such a value, then the executable's - EXIDX is probably the better choice. - */ - DEBUG_DUMP_PHDR(phdr, "PT_LOAD", pid); - if (phdr->p_vaddr + phdr->p_memsz > si->size) - si->size = phdr->p_vaddr + phdr->p_memsz; - /* try to remember what range of addresses should be write - * protected */ - if (!(phdr->p_flags & PF_W)) { - unsigned _end; - - if (phdr->p_vaddr < si->wrprotect_start) - si->wrprotect_start = phdr->p_vaddr; - _end = (((phdr->p_vaddr + phdr->p_memsz + PAGE_SIZE - 1) & - (~PAGE_MASK))); - if (_end > si->wrprotect_end) - si->wrprotect_end = _end; - } - } else if (phdr->p_type == PT_DYNAMIC) { - if (si->dynamic != (unsigned *)-1) { - DL_ERR("%5d multiple PT_DYNAMIC segments found in '%s'. " - "Segment at 0x%08x, previously one found at 0x%08x", - pid, si->name, si->base + phdr->p_vaddr, - (unsigned)si->dynamic); - goto fail; - } - DEBUG_DUMP_PHDR(phdr, "PT_DYNAMIC", pid); - si->dynamic = (unsigned *) (si->base + phdr->p_vaddr); - } - } - } - - if (si->dynamic == (unsigned *)-1) { - DL_ERR("%5d missing PT_DYNAMIC?!", pid); - goto fail; - } - - DEBUG("%5d dynamic = %p\n", pid, si->dynamic); - - /* extract useful information from dynamic section */ - for(d = si->dynamic; *d; d++){ - DEBUG("%5d d = %p, d[0] = 0x%08x d[1] = 0x%08x\n", pid, d, d[0], d[1]); - switch(*d++){ - case DT_HASH: - si->nbucket = ((unsigned *) (si->base + *d))[0]; - si->nchain = ((unsigned *) (si->base + *d))[1]; - si->bucket = (unsigned *) (si->base + *d + 8); - si->chain = (unsigned *) (si->base + *d + 8 + si->nbucket * 4); - break; - case DT_STRTAB: - si->strtab = (const char *) (si->base + *d); - break; - case DT_SYMTAB: - si->symtab = (Elf32_Sym *) (si->base + *d); - break; -#if !defined(ANDROID_SH_LINKER) - case DT_PLTREL: - if(*d != DT_REL) { - DL_ERR("DT_RELA not supported"); - goto fail; - } - break; -#endif -#ifdef ANDROID_SH_LINKER - case DT_JMPREL: - si->plt_rela = (Elf32_Rela*) (si->base + *d); - break; - case DT_PLTRELSZ: - si->plt_rela_count = *d / sizeof(Elf32_Rela); - break; -#else - case DT_JMPREL: - si->plt_rel = (Elf32_Rel*) (si->base + *d); - break; - case DT_PLTRELSZ: - si->plt_rel_count = *d / 8; - break; -#endif - case DT_REL: - si->rel = (Elf32_Rel*) (si->base + *d); - break; - case DT_RELSZ: - si->rel_count = *d / 8; - break; -#ifdef ANDROID_SH_LINKER - case DT_RELASZ: - si->rela_count = *d / sizeof(Elf32_Rela); - break; -#endif - case DT_PLTGOT: - /* Save this in case we decide to do lazy binding. We don't yet. */ - si->plt_got = (unsigned *)(si->base + *d); - break; - case DT_DEBUG: - // Set the DT_DEBUG entry to the addres of _r_debug for GDB - *d = (int) &_r_debug; - break; -#ifdef ANDROID_SH_LINKER - case DT_RELA: - si->rela = (Elf32_Rela *) (si->base + *d); - break; -#else - case DT_RELA: - DL_ERR("%5d DT_RELA not supported", pid); - goto fail; -#endif - case DT_INIT: - si->init_func = (void (*)(void))(si->base + *d); - DEBUG("%5d %s constructors (init func) found at %p\n", - pid, si->name, si->init_func); - break; - case DT_FINI: - si->fini_func = (void (*)(void))(si->base + *d); - DEBUG("%5d %s destructors (fini func) found at %p\n", - pid, si->name, si->fini_func); - break; - case DT_INIT_ARRAY: - si->init_array = (unsigned *)(si->base + *d); - DEBUG("%5d %s constructors (init_array) found at %p\n", - pid, si->name, si->init_array); - break; - case DT_INIT_ARRAYSZ: - si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); - break; - case DT_FINI_ARRAY: - si->fini_array = (unsigned *)(si->base + *d); - DEBUG("%5d %s destructors (fini_array) found at %p\n", - pid, si->name, si->fini_array); - break; - case DT_FINI_ARRAYSZ: - si->fini_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); - break; - case DT_PREINIT_ARRAY: - si->preinit_array = (unsigned *)(si->base + *d); - DEBUG("%5d %s constructors (preinit_array) found at %p\n", - pid, si->name, si->preinit_array); - break; - case DT_PREINIT_ARRAYSZ: - si->preinit_array_count = ((unsigned)*d) / sizeof(Elf32_Addr); - break; - case DT_TEXTREL: - /* TODO: make use of this. */ - /* this means that we might have to write into where the text - * segment was loaded during relocation... Do something with - * it. - */ - DEBUG("%5d Text segment should be writable during relocation.\n", - pid); - break; - } - } - - DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n", - pid, si->base, si->strtab, si->symtab); - - if((si->strtab == 0) || (si->symtab == 0)) { - DL_ERR("%5d missing essential tables", pid); - goto fail; - } - - /* if this is the main executable, then load all of the preloads now */ - if(si->flags & FLAG_EXE) { - int i; - memset(preloads, 0, sizeof(preloads)); - for(i = 0; ldpreload_names[i] != NULL; i++) { - soinfo *lsi = find_library(ldpreload_names[i]); - if(lsi == 0) { - strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf)); - DL_ERR("%5d could not load needed library '%s' for '%s' (%s)", - pid, ldpreload_names[i], si->name, tmp_err_buf); - goto fail; - } - lsi->refcount++; - preloads[i] = lsi; - } - } - - for(d = si->dynamic; *d; d += 2) { - if(d[0] == DT_NEEDED){ - DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]); - soinfo *lsi = find_library(si->strtab + d[1]); - if(lsi == 0) { - strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf)); - DL_ERR("%5d could not load needed library '%s' for '%s' (%s)", - pid, si->strtab + d[1], si->name, tmp_err_buf); - goto fail; - } - /* Save the soinfo of the loaded DT_NEEDED library in the payload - of the DT_NEEDED entry itself, so that we can retrieve the - soinfo directly later from the dynamic segment. This is a hack, - but it allows us to map from DT_NEEDED to soinfo efficiently - later on when we resolve relocations, trying to look up a symgol - with dlsym(). - */ - d[1] = (unsigned)lsi; - lsi->refcount++; - } - } - - if(si->plt_rel) { - DEBUG("[ %5d relocating %s plt ]\n", pid, si->name ); - if(reloc_library(si, si->plt_rel, si->plt_rel_count)) - goto fail; - } - if(si->rel) { - DEBUG("[ %5d relocating %s ]\n", pid, si->name ); - if(reloc_library(si, si->rel, si->rel_count)) - goto fail; - } - -#ifdef ANDROID_SH_LINKER - if(si->plt_rela) { - DEBUG("[ %5d relocating %s plt ]\n", pid, si->name ); - if(reloc_library_a(si, si->plt_rela, si->plt_rela_count)) - goto fail; - } - if(si->rela) { - DEBUG("[ %5d relocating %s ]\n", pid, si->name ); - if(reloc_library_a(si, si->rela, si->rela_count)) - goto fail; - } -#endif /* ANDROID_SH_LINKER */ - - si->flags |= FLAG_LINKED; - DEBUG("[ %5d finished linking %s ]\n", pid, si->name); - -#if 0 - /* This is the way that the old dynamic linker did protection of - * non-writable areas. It would scan section headers and find where - * .text ended (rather where .data/.bss began) and assume that this is - * the upper range of the non-writable area. This is too coarse, - * and is kept here for reference until we fully move away from single - * segment elf objects. See the code in get_wr_offset (also #if'd 0) - * that made this possible. - */ - if(wr_offset < 0xffffffff){ - mprotect((void*) si->base, wr_offset, PROT_READ | PROT_EXEC); - } -#else - /* TODO: Verify that this does the right thing in all cases, as it - * presently probably does not. It is possible that an ELF image will - * come with multiple read-only segments. What we ought to do is scan - * the program headers again and mprotect all the read-only segments. - * To prevent re-scanning the program header, we would have to build a - * list of loadable segments in si, and then scan that instead. */ - if (si->wrprotect_start != 0xffffffff && si->wrprotect_end != 0) { - mprotect((void *)si->wrprotect_start, - si->wrprotect_end - si->wrprotect_start, - PROT_READ | PROT_EXEC); - } -#endif - - /* If this is a SET?ID program, dup /dev/null to opened stdin, - stdout and stderr to close a security hole described in: - - ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc - - */ - if (program_is_setuid) - nullify_closed_stdio (); - notify_gdb_of_load(si); - call_constructors(si); - return 0; - -fail: - ERROR("failed to link %s\n", si->name); - si->flags |= FLAG_ERROR; - return -1; -} - -static void parse_library_path(const char *path, char *delim) -{ - size_t len; - char *ldpaths_bufp = ldpaths_buf; - int i = 0; - - len = strlcpy(ldpaths_buf, path, sizeof(ldpaths_buf)); - - while (i < LDPATH_MAX && (ldpaths[i] = strsep(&ldpaths_bufp, delim))) { - if (*ldpaths[i] != '\0') - ++i; - } - - /* Forget the last path if we had to truncate; this occurs if the 2nd to - * last char isn't '\0' (i.e. not originally a delim). */ - if (i > 0 && len >= sizeof(ldpaths_buf) && - ldpaths_buf[sizeof(ldpaths_buf) - 2] != '\0') { - ldpaths[i - 1] = NULL; - } else { - ldpaths[i] = NULL; - } -} - -static void parse_preloads(const char *path, char *delim) -{ - size_t len; - char *ldpreloads_bufp = ldpreloads_buf; - int i = 0; - - len = strlcpy(ldpreloads_buf, path, sizeof(ldpreloads_buf)); - - while (i < LDPRELOAD_MAX && (ldpreload_names[i] = strsep(&ldpreloads_bufp, delim))) { - if (*ldpreload_names[i] != '\0') { - ++i; - } - } - - /* Forget the last path if we had to truncate; this occurs if the 2nd to - * last char isn't '\0' (i.e. not originally a delim). */ - if (i > 0 && len >= sizeof(ldpreloads_buf) && - ldpreloads_buf[sizeof(ldpreloads_buf) - 2] != '\0') { - ldpreload_names[i - 1] = NULL; - } else { - ldpreload_names[i] = NULL; - } -} - -int main(int argc, char **argv) -{ - return 0; -} - -#define ANDROID_TLS_SLOTS BIONIC_TLS_SLOTS - -static void * __tls_area[ANDROID_TLS_SLOTS]; - -unsigned __linker_init(unsigned **elfdata) -{ - static soinfo linker_soinfo; - - int argc = (int) *elfdata; - char **argv = (char**) (elfdata + 1); - unsigned *vecs = (unsigned*) (argv + argc + 1); - soinfo *si; - struct link_map * map; - const char *ldpath_env = NULL; - const char *ldpreload_env = NULL; - - /* Setup a temporary TLS area that is used to get a working - * errno for system calls. - */ - //__set_tls(__tls_area); - - pid = getpid(); - -#if TIMING - struct timeval t0, t1; - gettimeofday(&t0, 0); -#endif - - /* NOTE: we store the elfdata pointer on a special location - * of the temporary TLS area in order to pass it to - * the C Library's runtime initializer. - * - * The initializer must clear the slot and reset the TLS - * to point to a different location to ensure that no other - * shared library constructor can access it. - */ -#if 0 - __libc_init_tls(elfdata); -#endif - - pid = getpid(); - -#if TIMING - struct timeval t0, t1; - gettimeofday(&t0, 0); -#endif - - /* Initialize environment functions, and get to the ELF aux vectors table */ - vecs = linker_env_init(vecs); - - /* Sanitize environment if we're loading a setuid program */ - if (program_is_setuid) - linker_env_secure(); - - //debugger_init(); - - /* Get a few environment variables */ - { - const char* env; - env = linker_env_get("DEBUG"); /* XXX: TODO: Change to LD_DEBUG */ - if (env) - debug_verbosity = atoi(env); - - /* Normally, these are cleaned by linker_env_secure, but the test - * against program_is_setuid doesn't cost us anything */ - if (!program_is_setuid) { - ldpath_env = linker_env_get("LD_LIBRARY_PATH"); - ldpreload_env = linker_env_get("LD_PRELOAD"); - } - } - - INFO("[ android linker & debugger ]\n"); - DEBUG("%5d elfdata @ 0x%08x\n", pid, (unsigned)elfdata); - - si = alloc_info(argv[0]); - if(si == 0) { - exit(-1); - } - - /* bootstrap the link map, the main exe always needs to be first */ - si->flags |= FLAG_EXE; - map = &(si->linkmap); - - map->l_addr = 0; - map->l_name = argv[0]; - map->l_prev = NULL; - map->l_next = NULL; - - _r_debug.r_map = map; - r_debug_tail = map; - - /* gdb expects the linker to be in the debug shared object list, - * and we need to make sure that the reported load address is zero. - * Without this, gdb gets the wrong idea of where rtld_db_dlactivity() - * is. Don't use alloc_info(), because the linker shouldn't - * be on the soinfo list. - */ - strlcpy((char*) linker_soinfo.name, "/system/bin/linker", sizeof linker_soinfo.name); - linker_soinfo.flags = 0; - linker_soinfo.base = 0; // This is the important part; must be zero. - insert_soinfo_into_debug_map(&linker_soinfo); - - /* extract information passed from the kernel */ - while(vecs[0] != 0){ - switch(vecs[0]){ - case AT_PHDR: - si->phdr = (Elf32_Phdr*) vecs[1]; - break; - case AT_PHNUM: - si->phnum = (int) vecs[1]; - break; - case AT_ENTRY: - si->entry = vecs[1]; - break; - } - vecs += 2; - } - - si->base = 0; - si->dynamic = (unsigned *)-1; - si->wrprotect_start = 0xffffffff; - si->wrprotect_end = 0; - si->refcount = 1; - - /* Use LD_LIBRARY_PATH if we aren't setuid/setgid */ - if (ldpath_env) - parse_library_path(ldpath_env, ":"); - - if (ldpreload_env) { - parse_preloads(ldpreload_env, " :"); - } - - if(link_image(si, 0)) { - char errmsg[] = "CANNOT LINK EXECUTABLE\n"; - write(2, __linker_dl_err_buf, strlen(__linker_dl_err_buf)); - write(2, errmsg, sizeof(errmsg)); - exit(-1); - } - -#if ALLOW_SYMBOLS_FROM_MAIN - /* Set somain after we've loaded all the libraries in order to prevent - * linking of symbols back to the main image, which is not set up at that - * point yet. - */ - somain = si; -#endif - -#if TIMING - gettimeofday(&t1,NULL); - PRINT("LINKER TIME: %s: %d microseconds\n", 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\n", argv[0], - linker_stats.reloc[RELOC_ABSOLUTE], - linker_stats.reloc[RELOC_RELATIVE], - linker_stats.reloc[RELOC_COPY], - linker_stats.reloc[RELOC_SYMBOL]); -#endif -#if COUNT_PAGES - { - unsigned n; - unsigned i; - unsigned count = 0; - for(n = 0; n < 4096; n++){ - if(bitmask[n]){ - unsigned x = bitmask[n]; - for(i = 0; i < 8; i++){ - if(x & 1) count++; - x >>= 1; - } - } - } - PRINT("PAGES MODIFIED: %s: %d (%dKB)\n", argv[0], count, count * 4); - } -#endif - -#if TIMING || STATS || COUNT_PAGES - fflush(stdout); -#endif - - TRACE("[ %5d Ready to execute '%s' @ 0x%08x ]\n", pid, si->name, - si->entry); - return si->entry; -} diff --git a/hybris/common/ics/linker.h b/hybris/common/ics/linker.h deleted file mode 100644 index 71af9d683..000000000 --- a/hybris/common/ics/linker.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * 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 -#include -#include - -#undef PAGE_MASK -#undef PAGE_SIZE -#define PAGE_SIZE 4096 -#define PAGE_MASK 4095 - -void debugger_init(); -const char *addr_to_name(unsigned addr); - -/* magic shared structures that GDB knows about */ - -struct link_map -{ - uintptr_t l_addr; - char * l_name; - uintptr_t l_ld; - struct link_map * l_next; - struct link_map * l_prev; -}; - -/* needed for dl_iterate_phdr to be passed to the callbacks provided */ -struct dl_phdr_info -{ - Elf32_Addr dlpi_addr; - const char *dlpi_name; - const Elf32_Phdr *dlpi_phdr; - Elf32_Half dlpi_phnum; -}; - - -// Values for r_debug->state -enum { - RT_CONSISTENT, - RT_ADD, - RT_DELETE -}; - -struct r_debug -{ - int32_t r_version; - struct link_map * r_map; - void (*r_brk)(void); - int32_t r_state; - uintptr_t r_ldbase; -}; - -typedef struct soinfo soinfo; - -#define FLAG_LINKED 0x00000001 -#define FLAG_ERROR 0x00000002 -#define FLAG_EXE 0x00000004 // The main executable - -#define SOINFO_NAME_LEN 128 - -struct soinfo -{ - const char name[SOINFO_NAME_LEN]; - Elf32_Phdr *phdr; - int phnum; - unsigned entry; - unsigned base; - unsigned size; - - int unused; // DO NOT USE, maintained for compatibility. - - unsigned *dynamic; - - unsigned wrprotect_start; - unsigned wrprotect_end; - - soinfo *next; - unsigned flags; - - const char *strtab; - Elf32_Sym *symtab; - - unsigned nbucket; - unsigned nchain; - unsigned *bucket; - unsigned *chain; - - unsigned *plt_got; - - Elf32_Rel *plt_rel; - unsigned plt_rel_count; - - Elf32_Rel *rel; - unsigned rel_count; - -#ifdef ANDROID_SH_LINKER - Elf32_Rela *plt_rela; - unsigned plt_rela_count; - - Elf32_Rela *rela; - unsigned rela_count; -#endif /* ANDROID_SH_LINKER */ - - unsigned *preinit_array; - unsigned preinit_array_count; - - unsigned *init_array; - unsigned init_array_count; - unsigned *fini_array; - unsigned fini_array_count; - - void (*init_func)(void); - void (*fini_func)(void); - -#ifdef ANDROID_ARM_LINKER - /* ARM EABI section used for stack unwinding. */ - unsigned *ARM_exidx; - unsigned ARM_exidx_count; -#endif - - unsigned refcount; - struct link_map linkmap; -}; - - -extern soinfo libdl_info; - -#ifdef ANDROID_ARM_LINKER - -#define R_ARM_COPY 20 -#define R_ARM_GLOB_DAT 21 -#define R_ARM_JUMP_SLOT 22 -#define R_ARM_RELATIVE 23 - -/* According to the AAPCS specification, we only - * need the above relocations. However, in practice, - * the following ones turn up from time to time. - */ -#define R_ARM_ABS32 2 -#define R_ARM_REL32 3 - -#elif defined(ANDROID_X86_LINKER) - -#define R_386_32 1 -#define R_386_PC32 2 -#define R_386_GLOB_DAT 6 -#define R_386_JUMP_SLOT 7 -#define R_386_RELATIVE 8 - -#elif defined(ANDROID_SH_LINKER) - -#define R_SH_DIR32 1 -#define R_SH_GLOB_DAT 163 -#define R_SH_JUMP_SLOT 164 -#define R_SH_RELATIVE 165 - -#endif /* ANDROID_*_LINKER */ - - -#ifndef DT_INIT_ARRAY -#define DT_INIT_ARRAY 25 -#endif - -#ifndef DT_FINI_ARRAY -#define DT_FINI_ARRAY 26 -#endif - -#ifndef DT_INIT_ARRAYSZ -#define DT_INIT_ARRAYSZ 27 -#endif - -#ifndef DT_FINI_ARRAYSZ -#define DT_FINI_ARRAYSZ 28 -#endif - -#ifndef DT_PREINIT_ARRAY -#define DT_PREINIT_ARRAY 32 -#endif - -#ifndef DT_PREINIT_ARRAYSZ -#define DT_PREINIT_ARRAYSZ 33 -#endif - -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); -soinfo *find_containing_library(const void *addr); -Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si); -const char *linker_get_error(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) || defined(ANDROID_SH_LINKER) -int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *); -#endif - -#endif diff --git a/hybris/common/ics/linker_debug.h b/hybris/common/ics/linker_debug.h deleted file mode 100644 index 3f08303ba..000000000 --- a/hybris/common/ics/linker_debug.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2008-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 _LINKER_DEBUG_H_ -#define _LINKER_DEBUG_H_ - -#include - -#ifndef LINKER_DEBUG -#error LINKER_DEBUG should be defined to either 1 or 0 in Android.mk -#endif - -/* set LINKER_DEBUG_TO_LOG to 1 to send the logs to logcat, - * or 0 to use stdout instead. - */ -#define LINKER_DEBUG_TO_LOG 1 -#define TRACE_DEBUG 1 -#define DO_TRACE_LOOKUP 1 -#define DO_TRACE_RELO 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 - *********************************************************************/ - - -/*********************************************************************/ -#undef TRUE -#undef FALSE -#define TRUE 1 -#define FALSE 0 - -/* Only use printf() during debugging. We have seen occasional memory - * corruption when the linker uses printf(). - */ -#if LINKER_DEBUG -#include "linker_format.h" -extern int debug_verbosity; -#if LINKER_DEBUG_TO_LOG -extern int format_log(int, const char *, const char *, ...); -#define _PRINTVF(v,f,x...) \ - do { \ - if (debug_verbosity > (v)) format_log(5-(v),"linker",x); \ - } while (0) -#else /* !LINKER_DEBUG_TO_LOG */ -extern int format_fd(int, const char *, ...); -#define _PRINTVF(v,f,x...) \ - do { \ - if (debug_verbosity > (v)) format_fd(1, x); \ - } while (0) -#endif /* !LINKER_DEBUG_TO_LOG */ -#else /* !LINKER_DEBUG */ -#define _PRINTVF(v,f,x...) do {} while(0) -#endif /* LINKER_DEBUG */ - -#define PRINT(x...) _PRINTVF(-1, FALSE, x) -#define INFO(x...) _PRINTVF(0, TRUE, x) -#define TRACE(x...) _PRINTVF(1, TRUE, x) -#define WARN(fmt,args...) \ - _PRINTVF(-1, TRUE, "%s:%d| WARNING: " fmt, __FILE__, __LINE__, ## args) -#define ERROR(fmt,args...) \ - _PRINTVF(-1, TRUE, "%s:%d| ERROR: " fmt, __FILE__, __LINE__, ## args) - - -#if TRACE_DEBUG -#define DEBUG(x...) _PRINTVF(2, TRUE, "DEBUG: " x) -#else /* !TRACE_DEBUG */ -#define DEBUG(x...) do {} while (0) -#endif /* TRACE_DEBUG */ - -#if LINKER_DEBUG -#define TRACE_TYPE(t,x...) do { if (DO_TRACE_##t) { TRACE(x); } } while (0) -#else /* !LINKER_DEBUG */ -#define TRACE_TYPE(t,x...) do {} while (0) -#endif /* LINKER_DEBUG */ - -#if STATS -#define RELOC_ABSOLUTE 0 -#define RELOC_RELATIVE 1 -#define RELOC_COPY 2 -#define RELOC_SYMBOL 3 -#define NUM_RELOC_STATS 4 - -struct _link_stats { - int reloc[NUM_RELOC_STATS]; -}; -extern struct _link_stats linker_stats; - -#define COUNT_RELOC(type) \ - do { if (type >= 0 && type < NUM_RELOC_STATS) { \ - linker_stats.reloc[type] += 1; \ - } else { \ - PRINT("Unknown reloc stat requested\n"); \ - } \ - } while(0) -#else /* !STATS */ -#define COUNT_RELOC(type) do {} while(0) -#endif /* STATS */ - -#if TIMING -#undef WARN -#define WARN(x...) do {} while (0) -#endif /* TIMING */ - -#if COUNT_PAGES -extern unsigned bitmask[]; -#define MARK(offset) do { \ - bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \ - } while(0) -#else -#define MARK(x) do {} while (0) -#endif - -#define DEBUG_DUMP_PHDR(phdr, name, pid) do { \ - DEBUG("%5d %s (phdr = 0x%08x)\n", (pid), (name), (unsigned)(phdr)); \ - DEBUG("\t\tphdr->offset = 0x%08x\n", (unsigned)((phdr)->p_offset)); \ - DEBUG("\t\tphdr->p_vaddr = 0x%08x\n", (unsigned)((phdr)->p_vaddr)); \ - DEBUG("\t\tphdr->p_paddr = 0x%08x\n", (unsigned)((phdr)->p_paddr)); \ - DEBUG("\t\tphdr->p_filesz = 0x%08x\n", (unsigned)((phdr)->p_filesz)); \ - DEBUG("\t\tphdr->p_memsz = 0x%08x\n", (unsigned)((phdr)->p_memsz)); \ - DEBUG("\t\tphdr->p_flags = 0x%08x\n", (unsigned)((phdr)->p_flags)); \ - DEBUG("\t\tphdr->p_align = 0x%08x\n", (unsigned)((phdr)->p_align)); \ - } while (0) - -#endif /* _LINKER_DEBUG_H_ */ diff --git a/hybris/common/ics/linker_environ.c b/hybris/common/ics/linker_environ.c deleted file mode 100644 index b71dd8069..000000000 --- a/hybris/common/ics/linker_environ.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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. - */ -#include "linker_environ.h" -#include - -static char** _envp; - -/* Returns 1 if 'str' points to a valid environment variable definition. - * For now, we check that: - * - It is smaller than MAX_ENV_LEN (to detect non-zero terminated strings) - * - It contains at least one equal sign that is not the first character - */ -static int -_is_valid_definition(const char* str) -{ - int pos = 0; - int first_equal_pos = -1; - - /* According to its sources, the kernel uses 32*PAGE_SIZE by default - * as the maximum size for an env. variable definition. - */ - const int MAX_ENV_LEN = 32*4096; - - if (str == NULL) - return 0; - - /* Parse the string, looking for the first '=' there, and its size */ - do { - if (str[pos] == '\0') - break; - if (str[pos] == '=' && first_equal_pos < 0) - first_equal_pos = pos; - pos++; - } while (pos < MAX_ENV_LEN); - - if (pos >= MAX_ENV_LEN) /* Too large */ - return 0; - - if (first_equal_pos < 1) /* No equal sign, or it is the first character */ - return 0; - - return 1; -} - -unsigned* -linker_env_init(unsigned* vecs) -{ - /* Store environment pointer - can't be NULL */ - _envp = (char**) vecs; - - /* Skip over all definitions */ - while (vecs[0] != 0) - vecs++; - /* The end of the environment block is marked by two NULL pointers */ - vecs++; - - /* As a sanity check, we're going to remove all invalid variable - * definitions from the environment array. - */ - { - char** readp = _envp; - char** writep = _envp; - for ( ; readp[0] != NULL; readp++ ) { - if (!_is_valid_definition(readp[0])) - continue; - writep[0] = readp[0]; - writep++; - } - writep[0] = NULL; - } - - /* Return the address of the aux vectors table */ - return vecs; -} - -/* Check if the environment variable definition at 'envstr' - * starts with '=', and if so return the address of the - * first character after the equal sign. Otherwise return NULL. - */ -static char* -env_match(char* envstr, const char* name) -{ - size_t cnt = 0; - - while (envstr[cnt] == name[cnt] && name[cnt] != '\0') - cnt++; - - if (name[cnt] == '\0' && envstr[cnt] == '=') - return envstr + cnt + 1; - - return NULL; -} - -#define MAX_ENV_LEN (16*4096) - -const char* -linker_env_get(const char* name) -{ - char** readp = _envp; - - if (name == NULL || name[0] == '\0') - return NULL; - - for ( ; readp[0] != NULL; readp++ ) { - char* val = env_match(readp[0], name); - if (val != NULL) { - /* Return NULL for empty strings, or if it is too large */ - if (val[0] == '\0') - val = NULL; - return val; - } - } - return NULL; -} - - -void -linker_env_unset(const char* name) -{ - char** readp = _envp; - char** writep = readp; - - if (name == NULL || name[0] == '\0') - return; - - for ( ; readp[0] != NULL; readp++ ) { - if (env_match(readp[0], name)) - continue; - writep[0] = readp[0]; - writep++; - } - /* end list with a NULL */ - writep[0] = NULL; -} - - - -/* Remove unsafe environment variables. This should be used when - * running setuid programs. */ -void -linker_env_secure(void) -{ - /* The same list than GLibc at this point */ - static const char* const unsec_vars[] = { - "GCONV_PATH", - "GETCONF_DIR", - "HOSTALIASES", - "LD_AUDIT", - "LD_DEBUG", - "LD_DEBUG_OUTPUT", - "LD_DYNAMIC_WEAK", - "LD_LIBRARY_PATH", - "LD_ORIGIN_PATH", - "LD_PRELOAD", - "LD_PROFILE", - "LD_SHOW_AUXV", - "LD_USE_LOAD_BIAS", - "LOCALDOMAIN", - "LOCPATH", - "MALLOC_TRACE", - "MALLOC_CHECK_", - "NIS_PATH", - "NLSPATH", - "RESOLV_HOST_CONF", - "RES_OPTIONS", - "TMPDIR", - "TZDIR", - "LD_AOUT_LIBRARY_PATH", - "LD_AOUT_PRELOAD", - }; - - const char* const* cp = unsec_vars; - const char* const* endp = cp + sizeof(unsec_vars)/sizeof(unsec_vars[0]); - - while (cp < endp) { - linker_env_unset(*cp); - cp++; - } -} diff --git a/hybris/common/ics/linker_format.c b/hybris/common/ics/linker_format.c deleted file mode 100644 index 92ece21c2..000000000 --- a/hybris/common/ics/linker_format.c +++ /dev/null @@ -1,707 +0,0 @@ -/* - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include "linker_format.h" -#include "linker_debug.h" - -/* define UNIT_TESTS to build this file as a single executable that runs - * the formatter's unit tests - */ -#define xxUNIT_TESTS - -/*** Generic output sink - ***/ - -typedef struct { - void *opaque; - void (*send)(void *opaque, const char *data, int len); -} Out; - -static void -out_send(Out *o, const void *data, size_t len) -{ - o->send(o->opaque, data, (int)len); -} - -static void -out_send_repeat(Out *o, char ch, int count) -{ - char pad[8]; - const int padSize = (int)sizeof(pad); - - memset(pad, ch, sizeof(pad)); - while (count > 0) { - int avail = count; - if (avail > padSize) { - avail = padSize; - } - o->send(o->opaque, pad, avail); - count -= avail; - } -} - -/* forward declaration */ -static void -out_vformat(Out *o, const char *format, va_list args); - -/*** Bounded buffer output - ***/ - -typedef struct { - Out out[1]; - char *buffer; - char *pos; - char *end; - int total; -} BufOut; - -static void -buf_out_send(void *opaque, const char *data, int len) -{ - BufOut *bo = opaque; - - if (len < 0) - len = strlen(data); - - bo->total += len; - - while (len > 0) { - int avail = bo->end - bo->pos; - if (avail == 0) - break; - if (avail > len) - avail = len; - memcpy(bo->pos, data, avail); - bo->pos += avail; - bo->pos[0] = '\0'; - len -= avail; - } -} - -static Out* -buf_out_init(BufOut *bo, char *buffer, size_t size) -{ - if (size == 0) - return NULL; - - bo->out->opaque = bo; - bo->out->send = buf_out_send; - bo->buffer = buffer; - bo->end = buffer + size - 1; - bo->pos = bo->buffer; - bo->pos[0] = '\0'; - bo->total = 0; - - return bo->out; -} - -static int -buf_out_length(BufOut *bo) -{ - return bo->total; -} - -static int -vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args) -{ - BufOut bo; - Out *out; - - out = buf_out_init(&bo, buff, buffsize); - if (out == NULL) - return 0; - - out_vformat(out, format, args); - - return buf_out_length(&bo); -} - -int -format_buffer(char *buff, size_t buffsize, const char *format, ...) -{ - va_list args; - int ret; - - va_start(args, format); - ret = vformat_buffer(buff, buffsize, format, args); - va_end(args); - - return ret; -} - -/* The __stack_chk_fail() function calls __libc_android_log_print() - * which calls vsnprintf(). - * - * We define our version of the function here to avoid dragging - * about 25 KB of C library routines related to formatting. - */ -#if 0 -int -vsnprintf(char *buff, size_t bufsize, const char *format, va_list args) -{ - return format_buffer(buff, bufsize, format, args); -} -#endif - -#if LINKER_DEBUG - -#if !LINKER_DEBUG_TO_LOG - -/*** File descriptor output - ***/ - -typedef struct { - Out out[1]; - int fd; - int total; -} FdOut; - -static void -fd_out_send(void *opaque, const char *data, int len) -{ - FdOut *fdo = opaque; - - if (len < 0) - len = strlen(data); - - while (len > 0) { - int ret = write(fdo->fd, data, len); - if (ret < 0) { - if (errno == EINTR) - continue; - break; - } - data += ret; - len -= ret; - fdo->total += ret; - } -} - -static Out* -fd_out_init(FdOut *fdo, int fd) -{ - fdo->out->opaque = fdo; - fdo->out->send = fd_out_send; - fdo->fd = fd; - fdo->total = 0; - - return fdo->out; -} - -static int -fd_out_length(FdOut *fdo) -{ - return fdo->total; -} - - -int -format_fd(int fd, const char *format, ...) -{ - FdOut fdo; - Out* out; - va_list args; - - out = fd_out_init(&fdo, fd); - if (out == NULL) - return 0; - - va_start(args, format); - out_vformat(out, format, args); - va_end(args); - - return fd_out_length(&fdo); -} - -#else /* LINKER_DEBUG_TO_LOG */ - -/*** Log output - ***/ - -/* We need our own version of __libc_android_log_vprint, otherwise - * the log output is completely broken. Probably due to the fact - * that the C library is not initialized yet. - * - * You can test that by setting CUSTOM_LOG_VPRINT to 0 - */ -#define CUSTOM_LOG_VPRINT 1 - -#if CUSTOM_LOG_VPRINT - -#include -#include -#include - -static int log_vprint(int prio, const char *tag, const char *fmt, va_list args) -{ - char buf[1024]; - int result; - static int log_fd = -1; - - result = vformat_buffer(buf, sizeof buf, fmt, args); - - if (log_fd < 0) { - log_fd = open("/dev/log/main", O_WRONLY); - if (log_fd < 0) - return result; - } - - { - ssize_t ret; - struct iovec vec[3]; - - vec[0].iov_base = (unsigned char *) &prio; - vec[0].iov_len = 1; - vec[1].iov_base = (void *) tag; - vec[1].iov_len = strlen(tag) + 1; - vec[2].iov_base = (void *) buf; - vec[2].iov_len = strlen(buf) + 1; - - do { - ret = writev(log_fd, vec, 3); - } while ((ret < 0) && (errno == EINTR)); - } - return result; -} - -#define __libc_android_log_vprint log_vprint - -#else /* !CUSTOM_LOG_VPRINT */ - -extern int __libc_android_log_vprint(int prio, const char* tag, const char* format, va_list ap); - -#endif /* !CUSTOM_LOG_VPRINT */ - -int -format_log(int prio, const char *tag, const char *format, ...) -{ - int ret; - va_list args; - va_start(args, format); - ret = __libc_android_log_vprint(prio, tag, format, args); - va_end(args); - return ret; -} - -#endif /* LINKER_DEBUG_TO_LOG */ - -#endif /* LINKER_DEBUG */ - -/*** formatted output implementation - ***/ - -/* Parse a decimal string from 'format + *ppos', - * return the value, and writes the new position past - * the decimal string in '*ppos' on exit. - * - * NOTE: Does *not* handle a sign prefix. - */ -static unsigned -parse_decimal(const char *format, int *ppos) -{ - const char* p = format + *ppos; - unsigned result = 0; - - for (;;) { - int ch = *p; - unsigned d = (unsigned)(ch - '0'); - - if (d >= 10U) - break; - - result = result*10 + d; - p++; - } - *ppos = p - format; - return result; -} - -/* write an octal/decimal/number into a bounded buffer. - * assumes that bufsize > 0, and 'digits' is a string of - * digits of at least 'base' values. - */ -static void -format_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits) -{ - char *pos = buffer; - char *end = buffer + bufsize - 1; - - /* generate digit string in reverse order */ - while (value) { - unsigned d = value % base; - value /= base; - if (pos < end) { - *pos++ = digits[d]; - } - } - - /* special case for 0 */ - if (pos == buffer) { - if (pos < end) { - *pos++ = '0'; - } - } - pos[0] = '\0'; - - /* now reverse digit string in-place */ - end = pos - 1; - pos = buffer; - while (pos < end) { - int ch = pos[0]; - pos[0] = end[0]; - end[0] = (char) ch; - pos++; - end--; - } -} - -/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */ -static void -format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned) -{ - if (isSigned && (int64_t)value < 0) { - buffer[0] = '-'; - buffer += 1; - buffsize -= 1; - value = (uint64_t)(-(int64_t)value); - } - - format_number(buffer, buffsize, value, base, "0123456789"); -} - -/* Write an octal into a buffer, assumes buffsize > 2 */ -static void -format_octal(char *buffer, size_t buffsize, uint64_t value, int isSigned) -{ - format_integer(buffer, buffsize, value, 8, isSigned); -} - -/* Write a decimal into a buffer, assumes buffsize > 2 */ -static void -format_decimal(char *buffer, size_t buffsize, uint64_t value, int isSigned) -{ - format_integer(buffer, buffsize, value, 10, isSigned); -} - -/* Write an hexadecimal into a buffer, isCap is true for capital alphas. - * Assumes bufsize > 2 */ -static void -format_hex(char *buffer, size_t buffsize, uint64_t value, int isCap) -{ - const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef"; - - format_number(buffer, buffsize, value, 16, digits); -} - - -/* Perform formatted output to an output target 'o' */ -static void -out_vformat(Out *o, const char *format, va_list args) -{ - int nn = 0; - - for (;;) { - int mm; - int padZero = 0; - int padLeft = 0; - char sign = '\0'; - int width = -1; - int prec = -1; - size_t bytelen = sizeof(int); - const char* str; - int slen; - char buffer[32]; /* temporary buffer used to format numbers */ - - char c; - - /* first, find all characters that are not 0 or '%' */ - /* then send them to the output directly */ - mm = nn; - do { - c = format[mm]; - if (c == '\0' || c == '%') - break; - mm++; - } while (1); - - if (mm > nn) { - out_send(o, format+nn, mm-nn); - nn = mm; - } - - /* is this it ? then exit */ - if (c == '\0') - break; - - /* nope, we are at a '%' modifier */ - nn++; // skip it - - /* parse flags */ - for (;;) { - c = format[nn++]; - if (c == '\0') { /* single trailing '%' ? */ - c = '%'; - out_send(o, &c, 1); - return; - } - else if (c == '0') { - padZero = 1; - continue; - } - else if (c == '-') { - padLeft = 1; - continue; - } - else if (c == ' ' || c == '+') { - sign = c; - continue; - } - break; - } - - /* parse field width */ - if ((c >= '0' && c <= '9')) { - nn --; - width = (int)parse_decimal(format, &nn); - c = format[nn++]; - } - - /* parse precision */ - if (c == '.') { - prec = (int)parse_decimal(format, &nn); - c = format[nn++]; - } - - /* length modifier */ - switch (c) { - case 'h': - bytelen = sizeof(short); - if (format[nn] == 'h') { - bytelen = sizeof(char); - nn += 1; - } - c = format[nn++]; - break; - case 'l': - bytelen = sizeof(long); - if (format[nn] == 'l') { - bytelen = sizeof(long long); - nn += 1; - } - c = format[nn++]; - break; - case 'z': - bytelen = sizeof(size_t); - c = format[nn++]; - break; - case 't': - bytelen = sizeof(ptrdiff_t); - c = format[nn++]; - break; - default: - ; - } - - /* conversion specifier */ - if (c == 's') { - /* string */ - str = va_arg(args, const char*); - } else if (c == 'c') { - /* character */ - /* NOTE: char is promoted to int when passed through the stack */ - buffer[0] = (char) va_arg(args, int); - buffer[1] = '\0'; - str = buffer; - } else if (c == 'p') { - uint64_t value = (uintptr_t) va_arg(args, void*); - buffer[0] = '0'; - buffer[1] = 'x'; - format_hex(buffer + 2, sizeof buffer-2, value, 0); - str = buffer; - } else { - /* integers - first read value from stack */ - uint64_t value; - int isSigned = (c == 'd' || c == 'i' || c == 'o'); - - /* NOTE: int8_t and int16_t are promoted to int when passed - * through the stack - */ - switch (bytelen) { - case 1: value = (uint8_t) va_arg(args, int); break; - case 2: value = (uint16_t) va_arg(args, int); break; - case 4: value = va_arg(args, uint32_t); break; - case 8: value = va_arg(args, uint64_t); break; - default: return; /* should not happen */ - } - - /* sign extension, if needed */ - if (isSigned) { - int shift = 64 - 8*bytelen; - value = (uint64_t)(((int64_t)(value << shift)) >> shift); - } - - /* format the number properly into our buffer */ - switch (c) { - case 'i': case 'd': - format_integer(buffer, sizeof buffer, value, 10, isSigned); - break; - case 'o': - format_integer(buffer, sizeof buffer, value, 8, isSigned); - break; - case 'x': case 'X': - format_hex(buffer, sizeof buffer, value, (c == 'X')); - break; - default: - buffer[0] = '\0'; - } - /* then point to it */ - str = buffer; - } - - /* if we are here, 'str' points to the content that must be - * outputted. handle padding and alignment now */ - - slen = strlen(str); - - if (slen < width && !padLeft) { - char padChar = padZero ? '0' : ' '; - out_send_repeat(o, padChar, width - slen); - } - - out_send(o, str, slen); - - if (slen < width && padLeft) { - char padChar = padZero ? '0' : ' '; - out_send_repeat(o, padChar, width - slen); - } - } -} - - -#ifdef UNIT_TESTS - -#include - -static int gFails = 0; - -#define MARGIN 40 - -#define UTEST_CHECK(condition,message) \ - printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \ - if (!(condition)) { \ - printf("KO\n"); \ - gFails += 1; \ - } else { \ - printf("ok\n"); \ - } - -static void -utest_BufOut(void) -{ - char buffer[16]; - BufOut bo[1]; - Out* out; - int ret; - - buffer[0] = '1'; - out = buf_out_init(bo, buffer, sizeof buffer); - UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte"); - out_send(out, "abc", 3); - UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut"); - out_send_repeat(out, 'X', 4); - UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut"); - buffer[sizeof buffer-1] = 'x'; - out_send_repeat(out, 'Y', 2*sizeof(buffer)); - UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates"); - - out = buf_out_init(bo, buffer, sizeof buffer); - out_send_repeat(out, 'X', 2*sizeof(buffer)); - ret = buf_out_length(bo); - UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow"); -} - -static void -utest_expect(const char* result, const char* format, ...) -{ - va_list args; - BufOut bo[1]; - char buffer[256]; - Out* out = buf_out_init(bo, buffer, sizeof buffer); - - printf("Checking %-*s: ", MARGIN, format); fflush(stdout); - va_start(args, format); - out_vformat(out, format, args); - va_end(args); - - if (strcmp(result, buffer)) { - printf("KO. got '%s' expecting '%s'\n", buffer, result); - gFails += 1; - } else { - printf("ok. got '%s'\n", result); - } -} - -int main(void) -{ - utest_BufOut(); - utest_expect("", ""); - utest_expect("a", "a"); - utest_expect("01234", "01234", ""); - utest_expect("01234", "%s", "01234"); - utest_expect("aabbcc", "aa%scc", "bb"); - utest_expect("a", "%c", 'a'); - utest_expect("1234", "%d", 1234); - utest_expect("-8123", "%d", -8123); - utest_expect("16", "%hd", 0x7fff0010); - utest_expect("16", "%hhd", 0x7fffff10); - utest_expect("68719476736", "%lld", 0x1000000000LL); - utest_expect("70000", "%ld", 70000); - utest_expect("0xb0001234", "%p", (void*)0xb0001234); - utest_expect("12ab", "%x", 0x12ab); - utest_expect("12AB", "%X", 0x12ab); - utest_expect("00123456", "%08x", 0x123456); - utest_expect("01234", "0%d", 1234); - utest_expect(" 1234", "%5d", 1234); - utest_expect("01234", "%05d", 1234); - utest_expect(" 1234", "%8d", 1234); - utest_expect("1234 ", "%-8d", 1234); - utest_expect("abcdef ", "%-11s", "abcdef"); - utest_expect("something:1234", "%s:%d", "something", 1234); - utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5); - utest_expect("5,0x0", "%d,%p", 5, NULL); - utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8); - return gFails != 0; -} - -#endif /* UNIT_TESTS */ diff --git a/hybris/common/ics/linker_format.h b/hybris/common/ics/linker_format.h deleted file mode 100644 index 6ae2badbf..000000000 --- a/hybris/common/ics/linker_format.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 _LINKER_FORMAT_H -#define _LINKER_FORMAT_H - -#include -#include - -/* Formatting routines for the dynamic linker's debug traces */ -/* We want to avoid dragging the whole C library fprintf() */ -/* implementation into the dynamic linker since this creates */ -/* issues (it uses malloc()/free()) and increases code size */ - -int format_buffer(char *buffer, size_t bufsize, const char *format, ...); - -#endif /* _LINKER_FORMAT_H */ diff --git a/hybris/common/jb/Makefile.am b/hybris/common/jb/Makefile.am index c95ea22f1..a348d4cfb 100644 --- a/hybris/common/jb/Makefile.am +++ b/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 diff --git a/hybris/common/jb/debugger.c b/hybris/common/jb/debugger.c index a84dc779e..74a310628 100644 --- a/hybris/common/jb/debugger.c +++ b/hybris/common/jb/debugger.c @@ -26,6 +26,8 @@ * SUCH DAMAGE. */ +#include "config.h" + #include #include #include diff --git a/hybris/common/jb/dlfcn.c b/hybris/common/jb/dlfcn.c index 382bfd2e0..78500e414 100644 --- a/hybris/common/jb/dlfcn.c +++ b/hybris/common/jb/dlfcn.c @@ -13,6 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +#include "config.h" + #include #include #include @@ -171,7 +174,7 @@ int android_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, vo // 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); @@ -223,20 +226,18 @@ static Elf_Sym libdl_symtab[] = { st_info: STB_GLOBAL << 4, st_shndx: 1, }, -#ifdef ANDROID_ARM_LINKER { st_name: 36, - st_value: (Elf_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: (Elf_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 +274,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, }; diff --git a/hybris/common/jb/linker.c b/hybris/common/jb/linker.c index 20333db35..61cef64ab 100644 --- a/hybris/common/jb/linker.c +++ b/hybris/common/jb/linker.c @@ -26,6 +26,8 @@ * SUCH DAMAGE. */ +#include "config.h" + #include #include @@ -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); @@ -1327,7 +1330,7 @@ static int reloc_library(soinfo *si, Elf_Rel *rel, unsigned count) 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); @@ -2333,3 +2336,8 @@ unsigned __linker_init(unsigned **elfdata) { // 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; +} diff --git a/hybris/common/jb/linker.h b/hybris/common/jb/linker.h index f57bdeb7f..a9d5d3ebe 100644 --- a/hybris/common/jb/linker.h +++ b/hybris/common/jb/linker.h @@ -229,11 +229,10 @@ 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 diff --git a/hybris/common/jb/linker_environ.c b/hybris/common/jb/linker_environ.c index b71dd8069..16dbb88e7 100644 --- a/hybris/common/jb/linker_environ.c +++ b/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 diff --git a/hybris/common/jb/linker_format.c b/hybris/common/jb/linker_format.c index 36b73d8be..b6bf8b3cc 100644 --- a/hybris/common/jb/linker_format.c +++ b/hybris/common/jb/linker_format.c @@ -26,6 +26,8 @@ * SUCH DAMAGE. */ +#include "config.h" + #include #include #include @@ -268,7 +270,7 @@ static int log_vprint(int prio, const char *tag, const char *fmt, va_list args) 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; diff --git a/hybris/common/gingerbread/MODULE_LICENSE_APACHE2 b/hybris/common/mm/MODULE_LICENSE_APACHE2 similarity index 100% rename from hybris/common/gingerbread/MODULE_LICENSE_APACHE2 rename to hybris/common/mm/MODULE_LICENSE_APACHE2 diff --git a/hybris/common/mm/Makefile.am b/hybris/common/mm/Makefile.am new file mode 100644 index 000000000..aadaf4b71 --- /dev/null +++ b/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 diff --git a/hybris/common/mm/NOTICE b/hybris/common/mm/NOTICE new file mode 100644 index 000000000..139b26eab --- /dev/null +++ b/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. + +------------------------------------------------------------------- + diff --git a/hybris/common/mm/bionic/libc/bionic/pthread_internal.h b/hybris/common/mm/bionic/libc/bionic/pthread_internal.h new file mode 100644 index 000000000..7f0a0b1ca --- /dev/null +++ b/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 +#include + +#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(__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_ */ diff --git a/hybris/common/ics/arch/arm/begin.S b/hybris/common/mm/bionic/libc/include/android/api-level.h similarity index 84% rename from hybris/common/ics/arch/arm/begin.S rename to hybris/common/mm/bionic/libc/include/android/api-level.h index e2599027a..2d2f0968c 100644 --- a/hybris/common/ics/arch/arm/begin.S +++ b/hybris/common/mm/bionic/libc/include/android/api-level.h @@ -26,20 +26,13 @@ * SUCH DAMAGE. */ - .text - .align 4 - .type _start,#function - .globl _start +#ifndef ANDROID_API_LEVEL_H +#define ANDROID_API_LEVEL_H -_start: - mov r0, sp - mov r1, #0 - bl __linker_init - - /* linker init returns the _entry address in the main image */ - mov pc, r0 +/* + * Magic version number for a current development build, which has + * not yet turned into an official release. + */ +#define __ANDROID_API__ 10000 - .section .ctors, "wa" - .globl __CTOR_LIST__ -__CTOR_LIST__: - .long -1 +#endif /* ANDROID_API_LEVEL_H */ diff --git a/hybris/common/mm/bionic/libc/include/android/dlext.h b/hybris/common/mm/bionic/libc/include/android/dlext.h new file mode 100644 index 000000000..40f610f29 --- /dev/null +++ b/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 +#include +#include +#include /* 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__ */ diff --git a/hybris/common/mm/bionic/libc/include/link.h b/hybris/common/mm/bionic/libc/include/link.h new file mode 100644 index 000000000..cb8e139ac --- /dev/null +++ b/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 +#include + +__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_ */ diff --git a/hybris/common/mm/bionic/libc/private/ErrnoRestorer.h b/hybris/common/mm/bionic/libc/private/ErrnoRestorer.h new file mode 100644 index 000000000..f4673936a --- /dev/null +++ b/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 + +#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 diff --git a/hybris/common/mm/bionic/libc/private/KernelArgumentBlock.h b/hybris/common/mm/bionic/libc/private/KernelArgumentBlock.h new file mode 100644 index 000000000..c8ea4977a --- /dev/null +++ b/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 +#include +#include +#include + +#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(raw_args); + argc = static_cast(*args); + argv = reinterpret_cast(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(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 diff --git a/hybris/common/mm/bionic/libc/private/NetdClientDispatch.h b/hybris/common/mm/bionic/libc/private/NetdClientDispatch.h new file mode 100644 index 000000000..db7a6b4d0 --- /dev/null +++ b/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 +#include + +__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 diff --git a/hybris/common/mm/bionic/libc/private/ScopeGuard.h b/hybris/common/mm/bionic/libc/private/ScopeGuard.h new file mode 100644 index 000000000..d5a9235d1 --- /dev/null +++ b/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 +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 +ScopeGuard make_scope_guard(T f) { + return ScopeGuard(f); +} + +#endif // _SCOPE_GUARD_H diff --git a/hybris/common/mm/bionic/libc/private/ScopedPthreadMutexLocker.h b/hybris/common/mm/bionic/libc/private/ScopedPthreadMutexLocker.h new file mode 100644 index 000000000..43dbdc115 --- /dev/null +++ b/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 + +#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 diff --git a/hybris/common/mm/bionic/libc/private/ScopedReaddir.h b/hybris/common/mm/bionic/libc/private/ScopedReaddir.h new file mode 100644 index 000000000..84c1b93a4 --- /dev/null +++ b/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 + +#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 diff --git a/hybris/common/mm/bionic/libc/private/ThreadLocalBuffer.h b/hybris/common/mm/bionic/libc/private/ThreadLocalBuffer.h new file mode 100644 index 000000000..5e436659a --- /dev/null +++ b/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 +#include + +// TODO: use __thread instead? + +template +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(pthread_getspecific(key_)); + if (result == nullptr) { + result = reinterpret_cast(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 diff --git a/hybris/common/mm/bionic/libc/private/UniquePtr.h b/hybris/common/mm/bionic/libc/private/UniquePtr.h new file mode 100644 index 000000000..5ac7599a0 --- /dev/null +++ b/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 +struct DefaultDelete { + enum { type_must_be_complete = sizeof(T) }; + DefaultDelete() {} + void operator()(T* p) const { + delete p; + } +}; + +// Default deleter for array types. +template +struct DefaultDelete { + 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(new C); +template > +class UniquePtr { +public: + // Construct a new UniquePtr, taking ownership of the given raw pointer. + explicit UniquePtr(T* ptr = nullptr) : mPtr(ptr) { } + + UniquePtr(UniquePtr&& 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 bool operator==(const UniquePtr& p) const = delete; + template bool operator!=(const UniquePtr& 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 +class UniquePtr { +public: + explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) { + } + UniquePtr(UniquePtr&& 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 diff --git a/hybris/common/mm/bionic/libc/private/__get_tls.h b/hybris/common/mm/bionic/libc/private/__get_tls.h new file mode 100644 index 000000000..04c5fdbbf --- /dev/null +++ b/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_ */ diff --git a/hybris/common/mm/bionic/libc/private/bionic_asm.h b/hybris/common/mm/bionic/libc/private/bionic_asm.h new file mode 100644 index 000000000..5fca222c4 --- /dev/null +++ b/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 /* 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 + +#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_ */ diff --git a/hybris/common/gingerbread/arch/arm/begin.S b/hybris/common/mm/bionic/libc/private/bionic_auxv.h similarity index 81% rename from hybris/common/gingerbread/arch/arm/begin.S rename to hybris/common/mm/bionic/libc/private/bionic_auxv.h index e2599027a..53fcc491b 100644 --- a/hybris/common/gingerbread/arch/arm/begin.S +++ b/hybris/common/mm/bionic/libc/private/bionic_auxv.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,21 +25,17 @@ * 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_ - .text - .align 4 - .type _start,#function - .globl _start +#include +#include +#include -_start: - mov r0, sp - mov r1, #0 - bl __linker_init +__BEGIN_DECLS - /* linker init returns the _entry address in the main image */ - mov pc, r0 +extern ElfW(auxv_t)* __libc_auxv; - .section .ctors, "wa" - .globl __CTOR_LIST__ -__CTOR_LIST__: - .long -1 +__END_DECLS + +#endif /* _PRIVATE_BIONIC_AUXV_H_ */ diff --git a/hybris/common/mm/bionic/libc/private/bionic_config.h b/hybris/common/mm/bionic/libc/private/bionic_config.h new file mode 100644 index 000000000..0c9811c0f --- /dev/null +++ b/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_ diff --git a/hybris/common/mm/bionic/libc/private/bionic_constants.h b/hybris/common/mm/bionic/libc/private/bionic_constants.h new file mode 100644 index 000000000..9ae1c8dd1 --- /dev/null +++ b/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_ diff --git a/hybris/common/mm/bionic/libc/private/bionic_futex.h b/hybris/common/mm/bionic/libc/private/bionic_futex.h new file mode 100644 index 000000000..401577ab8 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include + +__BEGIN_DECLS + +struct timespec; + +static inline __always_inline int __futex(volatile void* ftx, int op, int value, const struct timespec* timeout) { + // Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to. + int saved_errno = errno; + int result = syscall(__NR_futex, ftx, op, value, timeout); + if (__predict_false(result == -1)) { + result = -errno; + errno = saved_errno; + } + return result; +} + +static inline int __futex_wake(volatile void* ftx, int count) { + return __futex(ftx, FUTEX_WAKE, count, NULL); +} + +static inline int __futex_wake_ex(volatile void* ftx, bool shared, int count) { + return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL); +} + +static inline int __futex_wait(volatile void* ftx, int value, const struct timespec* timeout) { + return __futex(ftx, FUTEX_WAIT, value, timeout); +} + +static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value, const struct timespec* timeout) { + return __futex(ftx, shared ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE, value, timeout); +} + +__END_DECLS + +#endif /* _BIONIC_FUTEX_H */ diff --git a/hybris/common/ics/linker_environ.h b/hybris/common/mm/bionic/libc/private/bionic_lock.h similarity index 51% rename from hybris/common/ics/linker_environ.h rename to hybris/common/mm/bionic/libc/private/bionic_lock.h index 98ad1de27..6a0fd06ad 100644 --- a/hybris/common/ics/linker_environ.h +++ b/hybris/common/mm/bionic/libc/private/bionic_lock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2015 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,30 +25,50 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#ifndef LINKER_ENVIRON_H -#define LINKER_ENVIRON_H +#ifndef _BIONIC_LOCK_H +#define _BIONIC_LOCK_H -/* Call this function before anything else. 'vecs' must be the pointer - * to the environment block in the ELF data block. The function returns - * the start of the aux vectors after the env block. - */ -extern unsigned* linker_env_init(unsigned* vecs); +#include +#include "private/bionic_futex.h" + +class Lock { + private: + enum LockState { + Unlocked = 0, + LockedWithoutWaiter, + LockedWithWaiter, + }; + _Atomic(LockState) state; + bool process_shared; -/* Unset a given environment variable. In case the variable is defined - * multiple times, unset all instances. This modifies the environment - * block, so any pointer returned by linker_env_get() after this call - * might become invalid */ -extern void linker_env_unset(const char* name); + public: + Lock(bool process_shared = false) { + init(process_shared); + } + void init(bool process_shared) { + atomic_init(&state, Unlocked); + this->process_shared = process_shared; + } -/* Returns the value of environment variable 'name' if defined and not - * empty, or NULL otherwise. Note that the returned pointer may become - * invalid if linker_env_unset() or linker_env_secure() are called - * after this function. */ -extern const char* linker_env_get(const char* name); + 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; + } -/* Remove unsecure environment variables. This should be used when - * running setuid programs. */ -extern void linker_env_secure(void); + void unlock() { + if (atomic_exchange_explicit(&state, Unlocked, memory_order_release) == LockedWithWaiter) { + __futex_wake_ex(&state, process_shared, 1); + } + } +}; -#endif /* LINKER_ENVIRON_H */ +#endif // _BIONIC_LOCK_H diff --git a/hybris/common/mm/bionic/libc/private/bionic_macros.h b/hybris/common/mm/bionic/libc/private/bionic_macros.h new file mode 100644 index 000000000..4f3cf8997 --- /dev/null +++ b/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(value)))) \ + : (1UL << (32 - __builtin_clz(static_cast(value)))) + +#endif // _BIONIC_MACROS_H_ diff --git a/hybris/common/gingerbread/arch/x86/begin.S b/hybris/common/mm/bionic/libc/private/bionic_mbstate.h similarity index 63% rename from hybris/common/gingerbread/arch/x86/begin.S rename to hybris/common/mm/bionic/libc/private/bionic_mbstate.h index b4427e0cb..018b47ce2 100644 --- a/hybris/common/gingerbread/arch/x86/begin.S +++ b/hybris/common/mm/bionic/libc/private/bionic_mbstate.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2014 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,21 +26,29 @@ * SUCH DAMAGE. */ -.text -.align 4 -.type _start, @function -.globl _start +#ifndef _BIONIC_MBSTATE_H +#define _BIONIC_MBSTATE_H -_start: - /* save the elfdata ptr to %eax, AND push it onto the stack */ - mov %esp, %eax - pushl %esp +#include - pushl %eax - call __linker_init +__BEGIN_DECLS - /* linker init returns (%eax) the _entry address in the main image */ - /* entry point expects sp to point to elfdata */ - popl %esp - jmp *%eax +/* + * These return values are specified by POSIX for multibyte conversion + * functions. + */ +#define __MB_ERR_ILLEGAL_SEQUENCE static_cast(-1) +#define __MB_ERR_INCOMPLETE_SEQUENCE static_cast(-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 diff --git a/hybris/common/mm/bionic/libc/private/bionic_prctl.h b/hybris/common/mm/bionic/libc/private/bionic_prctl.h new file mode 100644 index 000000000..103cccb65 --- /dev/null +++ b/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 + +// 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 diff --git a/hybris/common/mm/bionic/libc/private/bionic_ssp.h b/hybris/common/mm/bionic/libc/private/bionic_ssp.h new file mode 100644 index 000000000..9883d7210 --- /dev/null +++ b/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 +#include + +__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 diff --git a/hybris/common/mm/bionic/libc/private/bionic_string_utils.h b/hybris/common/mm/bionic/libc/private/bionic_string_utils.h new file mode 100644 index 000000000..ab0eccf02 --- /dev/null +++ b/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 + +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_ diff --git a/hybris/common/mm/bionic/libc/private/bionic_systrace.h b/hybris/common/mm/bionic/libc/private/bionic_systrace.h new file mode 100644 index 000000000..09160be8d --- /dev/null +++ b/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 diff --git a/hybris/common/jb/arch/arm/begin.S b/hybris/common/mm/bionic/libc/private/bionic_time.h similarity index 81% rename from hybris/common/jb/arch/arm/begin.S rename to hybris/common/mm/bionic/libc/private/bionic_time.h index e2599027a..030dcfd99 100644 --- a/hybris/common/jb/arch/arm/begin.S +++ b/hybris/common/mm/bionic/libc/private/bionic_time.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,21 +25,17 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ +#ifndef _BIONIC_TIME_H +#define _BIONIC_TIME_H - .text - .align 4 - .type _start,#function - .globl _start +#include +#include -_start: - mov r0, sp - mov r1, #0 - bl __linker_init +__BEGIN_DECLS - /* linker init returns the _entry address in the main image */ - mov pc, r0 +// We can't remove this (and this file) until we fix MtpUtils.cpp. +time_t mktime_tz(struct tm* const, char const*); - .section .ctors, "wa" - .globl __CTOR_LIST__ -__CTOR_LIST__: - .long -1 +__END_DECLS + +#endif /* _BIONIC_TIME_H */ diff --git a/hybris/common/jb/arch/x86/begin.S b/hybris/common/mm/bionic/libc/private/bionic_time_conversions.h similarity index 74% rename from hybris/common/jb/arch/x86/begin.S rename to hybris/common/mm/bionic/libc/private/bionic_time_conversions.h index b4427e0cb..f75800301 100644 --- a/hybris/common/jb/arch/x86/begin.S +++ b/hybris/common/mm/bionic/libc/private/bionic_time_conversions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,21 +26,21 @@ * SUCH DAMAGE. */ -.text -.align 4 -.type _start, @function -.globl _start +#ifndef _BIONIC_TIME_CONVERSIONS_H +#define _BIONIC_TIME_CONVERSIONS_H -_start: - /* save the elfdata ptr to %eax, AND push it onto the stack */ - mov %esp, %eax - pushl %esp +#include +#include - pushl %eax - call __linker_init +__BEGIN_DECLS - /* linker init returns (%eax) the _entry address in the main image */ - /* entry point expects sp to point to elfdata */ - popl %esp - jmp *%eax + 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 diff --git a/hybris/common/mm/bionic/libc/private/bionic_tls.h b/hybris/common/mm/bionic/libc/private/bionic_tls.h new file mode 100644 index 000000000..22ca21248 --- /dev/null +++ b/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 +#include +#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_ */ diff --git a/hybris/common/mm/bionic/libc/private/kernel_sigset_t.h b/hybris/common/mm/bionic/libc/private/kernel_sigset_t.h new file mode 100644 index 000000000..9415fcf5d --- /dev/null +++ b/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 + +// 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 diff --git a/hybris/common/gingerbread/linker_format.h b/hybris/common/mm/bionic/libc/private/libc_events.h similarity index 60% rename from hybris/common/gingerbread/linker_format.h rename to hybris/common/mm/bionic/libc/private/libc_events.h index 6ae2badbf..f2b973d08 100644 --- a/hybris/common/gingerbread/linker_format.h +++ b/hybris/common/mm/bionic/libc/private/libc_events.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2013 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,17 +25,26 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#ifndef _LINKER_FORMAT_H -#define _LINKER_FORMAT_H -#include -#include +#ifndef _LIBC_EVENTS_H +#define _LIBC_EVENTS_H -/* Formatting routines for the dynamic linker's debug traces */ -/* We want to avoid dragging the whole C library fprintf() */ -/* implementation into the dynamic linker since this creates */ -/* issues (it uses malloc()/free()) and increases code size */ -int format_buffer(char *buffer, size_t bufsize, const char *format, ...); +// This is going to be included in assembler code so only allow #define +// values instead of defining an enum. -#endif /* _LINKER_FORMAT_H */ +#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 diff --git a/hybris/common/mm/bionic/libc/private/libc_logging.h b/hybris/common/mm/bionic/libc/private/libc_logging.h new file mode 100644 index 000000000..6beb47ec8 --- /dev/null +++ b/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 +#include +#include +#include + +__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 diff --git a/hybris/common/mm/bionic/libc/private/thread_private.h b/hybris/common/mm/bionic/libc/private/thread_private.h new file mode 100644 index 000000000..3c021575c --- /dev/null +++ b/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 */ + +#ifndef _THREAD_PRIVATE_H_ +#define _THREAD_PRIVATE_H_ + +#include + +__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_ */ diff --git a/hybris/common/mm/dlfcn.cpp b/hybris/common/mm/dlfcn.cpp new file mode 100644 index 000000000..699c2f5e2 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include + +#include +#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(__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(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(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(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(si->resolve_symbol_address(sym)); + } + + return 1; +} + +extern "C" int android_dlclose(void* handle) { + ScopedPthreadMutexLocker locker(&g_dl_mutex); + do_dlclose(reinterpret_cast(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(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(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; +} diff --git a/hybris/common/gingerbread/rt.c b/hybris/common/mm/hybris_compat.cpp similarity index 88% rename from hybris/common/gingerbread/rt.c rename to hybris/common/mm/hybris_compat.cpp index 30d5a4877..cfe1e78d3 100644 --- a/hybris/common/gingerbread/rt.c +++ b/hybris/common/mm/hybris_compat.cpp @@ -26,11 +26,4 @@ * SUCH DAMAGE. */ -/* - * This function is an empty stub where GDB locates a breakpoint to get notified - * about linker activity. - */ -void __attribute__((noinline)) rtld_db_dlactivity(void) -{ -} - +#include "hybris_compat.h" diff --git a/hybris/common/ics/arch/x86/begin.S b/hybris/common/mm/hybris_compat.h similarity index 69% rename from hybris/common/ics/arch/x86/begin.S rename to hybris/common/mm/hybris_compat.h index b4427e0cb..2e1038361 100644 --- a/hybris/common/ics/arch/x86/begin.S +++ b/hybris/common/mm/hybris_compat.h @@ -26,21 +26,33 @@ * SUCH DAMAGE. */ -.text -.align 4 -.type _start, @function -.globl _start -_start: - /* save the elfdata ptr to %eax, AND push it onto the stack */ - mov %esp, %eax - pushl %esp +#ifndef HYBRIS_ANDROID_MM_COMPAT_H_ +#define HYBRIS_ANDROID_MM_COMPAT_H_ - pushl %eax - call __linker_init +#include +#include - /* linker init returns (%eax) the _entry address in the main image */ - /* entry point expects sp to point to elfdata */ - popl %esp - jmp *%eax +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 diff --git a/hybris/common/mm/linked_list.h b/hybris/common/mm/linked_list.h new file mode 100644 index 000000000..8003dbf84 --- /dev/null +++ b/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 +struct LinkedListEntry { + LinkedListEntry* next; + T* element; +}; + +/* + * Represents linked list of objects of type T + */ +template +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* 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* 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* 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* p = head_; + head_ = head_->next; + Allocator::free(p); + } + + tail_ = nullptr; + } + + template + void for_each(F action) const { + visit([&] (T* si) { + action(si); + return true; + }); + } + + template + bool visit(F action) const { + for (LinkedListEntry* e = head_; e != nullptr; e = e->next) { + if (!action(e->element)) { + return false; + } + } + return true; + } + + template + void remove_if(F predicate) { + for (LinkedListEntry* e = head_, *p = nullptr; e != nullptr;) { + if (predicate(e->element)) { + LinkedListEntry* next = e->next; + if (p == nullptr) { + head_ = next; + } else { + p->next = next; + } + Allocator::free(e); + e = next; + } else { + p = e; + e = e->next; + } + } + } + + template + T* find_if(F predicate) const { + for (LinkedListEntry* 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* e = head_; sz < array_length && e != nullptr; e = e->next) { + array[sz++] = e->element; + } + + return sz; + } + + bool contains(const T* el) const { + for (LinkedListEntry* e = head_; e != nullptr; e = e->next) { + if (e->element == el) { + return true; + } + } + return false; + } + + static LinkedList make_list(T* const element) { + LinkedList one_element_list; + one_element_list.push_back(element); + return one_element_list; + } + + private: + LinkedListEntry* head_; + LinkedListEntry* tail_; + DISALLOW_COPY_AND_ASSIGN(LinkedList); +}; + +#endif // __LINKED_LIST_H diff --git a/hybris/common/mm/linker.cpp b/hybris/common/mm/linker.cpp new file mode 100644 index 000000000..cc41296f3 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// 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(x) & 0xf) + +static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr)* elf); + +static LinkerTypeAllocator g_soinfo_allocator; +static LinkerTypeAllocator> 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 g_ld_library_paths; +static std::vector g_ld_preload_names; + +static std::vector 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(&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(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* SoinfoListAllocator::alloc() { + return g_soinfo_links_allocator.alloc(); +} + +void SoinfoListAllocator::free(LinkedListEntry* 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(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* 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 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(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 +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_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(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(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(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(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(s->st_value), + static_cast(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(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(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(s->st_value), + static_cast(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(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(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(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(s->st_value), + (*si_found_in)->get_realpath(), reinterpret_cast((*si_found_in)->base), + reinterpret_cast((*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 +class SizeBasedAllocator { + public: + static void* alloc() { + return allocator_.alloc(); + } + + static void free(void* ptr) { + allocator_.free(ptr); + } + + private: + static LinkerBlockAllocator allocator_; +}; + +template +LinkerBlockAllocator SizeBasedAllocator::allocator_(size); + +template +class TypeBasedAllocator { + public: + static T* alloc() { + return reinterpret_cast(SizeBasedAllocator::alloc()); + } + + static void free(T* ptr) { + SizeBasedAllocator::free(ptr); + } +}; + +class LoadTask { + public: + struct deleter_t { + void operator()(LoadTask* t) { + TypeBasedAllocator::free(t); + } + }; + + typedef UniquePtr unique_ptr; + + static deleter_t deleter; + + static LoadTask* create(const char* name, soinfo* needed_by) { + LoadTask* ptr = TypeBasedAllocator::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 +using linked_list_t = LinkedList>>; + +typedef linked_list_t SoinfoLinkedList; +typedef linked_list_t StringLinkedList; +typedef linked_list_t 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 +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(s->st_value), reinterpret_cast((*found)->base)); + } + + return s; +} + +soinfo* find_containing_library(const void* p) { + ElfW(Addr) address = reinterpret_cast(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(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(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(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 +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* 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(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; iget_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(resolver_addr); + ElfW(Addr) ifunc_addr = ifunc_resolver(); + TRACE_TYPE(RELO, "Called ifunc_resolver@%p. The result is %p", + ifunc_resolver, reinterpret_cast(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_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; jvn_cnt; ++j) { + const ElfW(Vernaux)* vernaux = reinterpret_cast(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(reloc_addr); + } + return 0; +} +#endif + +template +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(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(_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(reloc), + reinterpret_cast(sym_addr + addend), sym_name); + + *reinterpret_cast(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(reloc), + reinterpret_cast(sym_addr + addend), sym_name); + *reinterpret_cast(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(reloc), + reinterpret_cast(load_bias + addend)); + *reinterpret_cast(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(reloc), + reinterpret_cast(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(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(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(reloc); + const ElfW(Addr) min_value = static_cast(INT32_MIN); + const ElfW(Addr) max_value = static_cast(UINT32_MAX); + if ((min_value <= (reloc_value + (sym_addr + addend))) && + ((reloc_value + (sym_addr + addend)) <= max_value)) { + *reinterpret_cast(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(reloc); + const ElfW(Addr) min_value = static_cast(INT16_MIN); + const ElfW(Addr) max_value = static_cast(UINT16_MAX); + if ((min_value <= (reloc_value + (sym_addr + addend))) && + ((reloc_value + (sym_addr + addend)) <= max_value)) { + *reinterpret_cast(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(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(reloc); + const ElfW(Addr) min_value = static_cast(INT32_MIN); + const ElfW(Addr) max_value = static_cast(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(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(reloc); + const ElfW(Addr) min_value = static_cast(INT16_MIN); + const ElfW(Addr) max_value = static_cast(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(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(reloc), + static_cast(sym_addr), sym_name); + *reinterpret_cast(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(reloc), + static_cast(sym_addr), sym_name); + *reinterpret_cast(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(reloc), static_cast(sym_addr - reloc), + static_cast(sym_addr), static_cast(reloc), sym_name); + *reinterpret_cast(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(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(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(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(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(function) == static_cast(-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(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(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(d->d_tag), reinterpret_cast(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(load_bias + d->d_un.d_ptr)[0]; + nchain_ = reinterpret_cast(load_bias + d->d_un.d_ptr)[1]; + bucket_ = reinterpret_cast(load_bias + d->d_un.d_ptr + 8); + chain_ = reinterpret_cast(load_bias + d->d_un.d_ptr + 8 + nbucket_ * 4); + break; + + case DT_GNU_HASH: + gnu_nbucket_ = reinterpret_cast(load_bias + d->d_un.d_ptr)[0]; + // skip symndx + gnu_maskwords_ = reinterpret_cast(load_bias + d->d_un.d_ptr)[2]; + gnu_shift2_ = reinterpret_cast(load_bias + d->d_un.d_ptr)[3]; + + gnu_bloom_filter_ = reinterpret_cast(load_bias + d->d_un.d_ptr + 16); + gnu_bucket_ = reinterpret_cast(gnu_bloom_filter_ + gnu_maskwords_); + // amend chain for symndx = header[1] + gnu_chain_ = gnu_bucket_ + gnu_nbucket_ - + reinterpret_cast(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(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(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(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(load_bias + d->d_un.d_ptr); +#else + plt_rel_ = reinterpret_cast(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(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(&_r_debug); + } +#endif + break; +#if defined(USE_RELA) + case DT_RELA: + rela_ = reinterpret_cast(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(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(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(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(d->d_un.d_val)); + return false; + } + break; + + case DT_ANDROID_REL: + android_relocs_ = reinterpret_cast(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(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(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(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(d->d_un.d_val) / sizeof(ElfW(Addr)); + break; + + case DT_FINI_ARRAY: + fini_array_ = reinterpret_cast(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(d->d_un.d_val) / sizeof(ElfW(Addr)); + break; + + case DT_PREINIT_ARRAY: + preinit_array_ = reinterpret_cast(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(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(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(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( + reinterpret_cast(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(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(d->d_tag), reinterpret_cast(d->d_un.d_val)); + } + break; + } + } + + DEBUG("si->base = %p, si->strtab = %p, si->symtab = %p", + reinterpret_cast(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(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(args.getauxval(AT_SYSINFO_EHDR)); + if (ehdr_vdso == nullptr) { + return; + } + + soinfo* si = soinfo_alloc("[vdso]", nullptr, 0, 0); + + si->phdr = reinterpret_cast(reinterpret_cast(ehdr_vdso) + ehdr_vdso->e_phoff); + si->phnum = ehdr_vdso->e_phnum; + si->base = reinterpret_cast(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(linker_base); + ElfW(Phdr)* phdr = reinterpret_cast(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(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(si->phdr) - si->phdr[i].p_vaddr; + si->base = reinterpret_cast(si->phdr) - si->phdr[i].p_offset; + break; + } + } + si->dynamic = nullptr; + + ElfW(Ehdr)* elf_hdr = reinterpret_cast(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(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(reinterpret_cast(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(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(linker_addr); + ElfW(Phdr)* phdr = reinterpret_cast(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(&_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 diff --git a/hybris/common/mm/linker.h b/hybris/common/mm/linker.h new file mode 100644 index 000000000..772497708 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +#include "private/libc_logging.h" +#include "linked_list.h" + +#include +#include + +#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* alloc(); + static void free(LinkedListEntry* 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_infos; + + DISALLOW_COPY_AND_ASSIGN(VersionTracker); +}; + +struct soinfo { + public: + typedef LinkedList 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 + 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 diff --git a/hybris/common/mm/linker_allocator.cpp b/hybris/common/mm/linker_allocator.cpp new file mode 100644 index 000000000..79092b0c2 --- /dev/null +++ b/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 +#include + +#include +#include +#include + +#include + +#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( + reinterpret_cast(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(page_record->page_addr); + void* page_end = reinterpret_cast(reinterpret_cast(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(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(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(PAGE_START(reinterpret_cast(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(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(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(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_START(reinterpret_cast(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]; +} diff --git a/hybris/common/mm/linker_allocator.h b/hybris/common/mm/linker_allocator.h new file mode 100644 index 000000000..2adad56fe --- /dev/null +++ b/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 +#include +#include +#include +#include + +#include + +#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 +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(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(ptr); + } + + void deallocate(T* ptr, size_t n) { + munmap(ptr, n * sizeof(T)); + } +}; + +typedef + std::vector> + 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 */ diff --git a/hybris/common/mm/linker_block_allocator.cpp b/hybris/common/mm/linker_block_allocator.cpp new file mode 100644 index 000000000..f6aacf648 --- /dev/null +++ b/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 +#include +#include +#include + +#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(free_block_list_); + if (block_info->num_free_blocks > 1) { + FreeBlockInfo* next_block_info = reinterpret_cast( + reinterpret_cast(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(block) - page->bytes; + + if (offset % block_size_ != 0) { + abort(); + } + + memset(block, 0, block_size_); + + FreeBlockInfo* block_info = reinterpret_cast(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( + 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(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(page); + if (block >= (page_ptr + sizeof(page->next)) && block < (page_ptr + PAGE_SIZE)) { + return page; + } + + page = page->next; + } + + abort(); +} diff --git a/hybris/common/mm/linker_block_allocator.h b/hybris/common/mm/linker_block_allocator.h new file mode 100644 index 000000000..4b9b99526 --- /dev/null +++ b/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 +#include +#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 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 +class LinkerTypeAllocator { + public: + LinkerTypeAllocator() : block_allocator_(sizeof(T)) {} + T* alloc() { return reinterpret_cast(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 diff --git a/hybris/common/mm/linker_debug.h b/hybris/common/mm/linker_debug.h new file mode 100644 index 000000000..2d1d39f43 --- /dev/null +++ b/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_ */ diff --git a/hybris/common/mm/linker_libc_support.c b/hybris/common/mm/linker_libc_support.c new file mode 100644 index 000000000..4c49384bf --- /dev/null +++ b/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; +} diff --git a/hybris/common/mm/linker_memory.cpp b/hybris/common/mm/linker_memory.cpp new file mode 100644 index 000000000..5f0515051 --- /dev/null +++ b/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 + +#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 + diff --git a/hybris/common/mm/linker_phdr.cpp b/hybris/common/mm/linker_phdr.cpp new file mode 100644 index 000000000..5d0680b1a --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +#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(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(reinterpret_cast(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(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(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(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(phdr->p_offset), + reinterpret_cast(phdr->p_filesz), + reinterpret_cast(file_end), file_size_); + return false; + } + + if (file_length != 0) { + void* seg_addr = mmap64(reinterpret_cast(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(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(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(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(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(seg_page_start), size)); + if (written != size) { + return -1; + } + void* map = mmap(reinterpret_cast(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(temp_mapping) + file_offset; + char* mem_base = reinterpret_cast(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(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(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(elf_addr); + ElfW(Addr) offset = ehdr->e_phoff; + return CheckPhdr(reinterpret_cast(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(loaded); + return true; + } + } + DL_ERR("\"%s\" loaded phdr %p not in loadable segment", name_, reinterpret_cast(loaded)); + return false; +} diff --git a/hybris/common/mm/linker_phdr.h b/hybris/common/mm/linker_phdr.h new file mode 100644 index 000000000..3affa66cd --- /dev/null +++ b/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(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 */ diff --git a/hybris/common/mm/linker_reloc_iterators.h b/hybris/common/mm/linker_reloc_iterators.h new file mode 100644 index 000000000..f28c0e0d7 --- /dev/null +++ b/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 + +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 +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 diff --git a/hybris/common/mm/linker_relocs.h b/hybris/common/mm/linker_relocs.h new file mode 100644 index 000000000..12c14974c --- /dev/null +++ b/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 + +#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 diff --git a/hybris/common/mm/linker_sdk_versions.cpp b/hybris/common/mm/linker_sdk_versions.cpp new file mode 100644 index 000000000..9aebb06ad --- /dev/null +++ b/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 +#include + +static std::atomic 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; +} + diff --git a/hybris/common/mm/linker_sleb128.h b/hybris/common/mm/linker_sleb128.h new file mode 100644 index 000000000..a34916f87 --- /dev/null +++ b/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 + +// 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(byte & 127) << shift); + shift += 7; + } while (byte & 128); + + if (shift < size && (byte & 64)) { + value |= -(static_cast(1) << shift); + } + + return value; + } + + private: + const uint8_t* current_; + const uint8_t* const end_; +}; + +#endif // __LINKER_SLEB128_H diff --git a/hybris/common/ics/rt.c b/hybris/common/mm/rt.cpp similarity index 89% rename from hybris/common/ics/rt.c rename to hybris/common/mm/rt.cpp index 30d5a4877..710892a03 100644 --- a/hybris/common/ics/rt.c +++ b/hybris/common/mm/rt.cpp @@ -28,9 +28,8 @@ /* * This function is an empty stub where GDB locates a breakpoint to get notified - * about linker activity. + * about linker activity. It canʼt be inlined away, can't be hidden. */ -void __attribute__((noinline)) rtld_db_dlactivity(void) -{ +extern "C" void __attribute__((noinline)) __attribute__((visibility("default"))) rtld_db_dlactivity() { } diff --git a/hybris/common/strlcat.c b/hybris/common/strlcat.c new file mode 100644 index 000000000..2b6f1adbb --- /dev/null +++ b/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 + * + * 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 +#include + +/* + * 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 */ +} diff --git a/hybris/common/stub/Makefile.am b/hybris/common/stub/Makefile.am new file mode 100644 index 000000000..74a56b444 --- /dev/null +++ b/hybris/common/stub/Makefile.am @@ -0,0 +1,4 @@ +noinst_LTLIBRARIES = \ + libstub-linker.la +libstub_linker_la_SOURCES = \ + linker.c diff --git a/hybris/common/stub/linker.c b/hybris/common/stub/linker.c new file mode 100644 index 000000000..5926ba3a4 --- /dev/null +++ b/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 +#include + +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; +} diff --git a/hybris/common/sysconf.c b/hybris/common/sysconf.c index 93535cc0f..58d833c33 100644 --- a/hybris/common/sysconf.c +++ b/hybris/common/sysconf.c @@ -1,8 +1,27 @@ +/* + * Copyright (c) 2013 Adrian Negreanu + * + * 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 /* - * 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]); } diff --git a/hybris/configure.ac b/hybris/configure.ac index 76607b4af..d89ed66d9 100644 --- a/hybris/configure.ac +++ b/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], @@ -79,6 +85,11 @@ AC_ARG_ENABLE(property_cache, [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) @@ -86,8 +97,12 @@ AC_ARG_ENABLE(arch, 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!" @@ -98,7 +113,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, @@ -107,7 +124,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" ], @@ -121,7 +142,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" @@ -185,15 +209,28 @@ AM_CONDITIONAL([HAS_ANDROID_4_0_3], [test $android_headers_major -ge 4 -a $andro 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 + camera/Makefile + camera/libcamera.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 @@ -218,8 +255,17 @@ AC_CONFIG_FILES([ libsync/libsync.pc vibrator/Makefile vibrator/libvibrator.pc + media/Makefile + media/libmedia.pc + wifi/Makefile + wifi/libwifi.pc include/Makefile + input/Makefile + input/libis.pc + ui/Makefile utils/Makefile + sf/Makefile + sf/libsf.pc tests/Makefile ]) @@ -237,16 +283,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." diff --git a/hybris/egl/egl.c b/hybris/egl/egl.c index cbbf88f05..f6dcd09a8 100644 --- a/hybris/egl/egl.c +++ b/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 #include #include @@ -244,8 +244,11 @@ EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, HYBRIS_TRACE_BEGIN("native-egl", "eglCreateWindowSurface", ""); EGLSurface result = (*_eglCreateWindowSurface)(dpy, config, 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, win); HYBRIS_TRACE_END("hybris-egl", "eglCreateWindowSurface", ""); return result; @@ -284,7 +287,6 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) { EGLBoolean ret; EGLSurface surface; - EGLNativeWindowType win; HYBRIS_TRACE_BEGIN("hybris-egl", "eglSwapInterval", "=%d", interval); /* Some egl implementations don't pass through the setSwapInterval diff --git a/hybris/glesv1/glesv1_cm.c b/hybris/glesv1/glesv1_cm.c index 1c383d4f4..3c2519cec 100644 --- a/hybris/glesv1/glesv1_cm.c +++ b/hybris/glesv1/glesv1_cm.c @@ -26,7 +26,7 @@ #include -#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); diff --git a/hybris/glesv2/glesv2.c b/hybris/glesv2/glesv2.c index 07f3df968..41113cfa5 100644 --- a/hybris/glesv2/glesv2.c +++ b/hybris/glesv2/glesv2.c @@ -23,40 +23,19 @@ #include #include -#include #include -#include static void *_libglesv2 = NULL; -/* Only functions with floating point argument need a wrapper to change the call convention correctly */ - -static void (*_glBlendColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) FP_ATTRIB = 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 (*_glDepthRangef)(GLclampf zNear, GLclampf zFar) FP_ATTRIB = NULL; -static void (*_glLineWidth)(GLfloat width) FP_ATTRIB = NULL; -static void (*_glPolygonOffset)(GLfloat factor, GLfloat units) FP_ATTRIB = NULL; -static void (*_glSampleCoverage)(GLclampf value, GLboolean invert) FP_ATTRIB = NULL; -static void (*_glTexParameterf)(GLenum target, GLenum pname, GLfloat param) FP_ATTRIB = NULL; -static void (*_glUniform1f)(GLint location, GLfloat x) FP_ATTRIB = NULL; -static void (*_glUniform2f)(GLint location, GLfloat x, GLfloat y) FP_ATTRIB = NULL; -static void (*_glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z) FP_ATTRIB = NULL; -static void (*_glUniform4f)(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) FP_ATTRIB = NULL; -static void (*_glVertexAttrib1f)(GLuint indx, GLfloat x) FP_ATTRIB = NULL; -static void (*_glVertexAttrib2f)(GLuint indx, GLfloat x, GLfloat y) FP_ATTRIB = NULL; -static void (*_glVertexAttrib3f)(GLuint indx, GLfloat x, GLfloat y, GLfloat z) FP_ATTRIB = 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 (*_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 framebuffer) = NULL; +static void (*_glBindRenderbuffer)(GLenum target, GLuint renderbuffer) = NULL; static void (*_glBindTexture)(GLenum target, GLuint texture) = NULL; -static void (*_glBlendEquation)(GLenum mode) = 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; @@ -64,6 +43,8 @@ static void (*_glBufferData)(GLenum target, GLsizeiptr size, const GLvoi 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; @@ -75,13 +56,14 @@ 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* 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; @@ -133,11 +115,14 @@ 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; @@ -148,19 +133,24 @@ 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; @@ -169,51 +159,23 @@ static void (*_glUniformMatrix3fv)(GLint location, GLsizei count, GLbool 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 (*_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) \ -{ \ - if (_libglesv2) \ - return (void *) android_dlsym(_libglesv2, #sym); \ - else \ - return &sym ## _wrapper; \ -} - static void __attribute__((constructor)) _init_androidglesv2() { _libglesv2 = (void *) android_dlopen(getenv("LIBGLESV2") ? getenv("LIBGLESV2") : "libGLESv2.so", RTLD_NOW); - GLES2_LOAD(glBlendColor); - GLES2_LOAD(glClearColor); - GLES2_LOAD(glClearDepthf); - GLES2_LOAD(glDepthRangef); - GLES2_LOAD(glLineWidth); - GLES2_LOAD(glPolygonOffset); - GLES2_LOAD(glSampleCoverage); - GLES2_LOAD(glTexParameterf); - GLES2_LOAD(glUniform1f); - GLES2_LOAD(glUniform2f); - GLES2_LOAD(glUniform3f); - GLES2_LOAD(glUniform4f); - GLES2_LOAD(glVertexAttrib1f); - GLES2_LOAD(glVertexAttrib2f); - GLES2_LOAD(glVertexAttrib3f); - GLES2_LOAD(glVertexAttrib4f); - GLES2_LOAD(glEGLImageTargetTexture2DOES); - GLES2_LOAD(glActiveTexture); GLES2_LOAD(glAttachShader); GLES2_LOAD(glBindAttribLocation); @@ -221,6 +183,7 @@ static void __attribute__((constructor)) _init_androidglesv2() { GLES2_LOAD(glBindFramebuffer); GLES2_LOAD(glBindRenderbuffer); GLES2_LOAD(glBindTexture); + GLES2_LOAD(glBlendColor); GLES2_LOAD(glBlendEquation); GLES2_LOAD(glBlendEquationSeparate); GLES2_LOAD(glBlendFunc); @@ -229,6 +192,8 @@ static void __attribute__((constructor)) _init_androidglesv2() { GLES2_LOAD(glBufferSubData); GLES2_LOAD(glCheckFramebufferStatus); GLES2_LOAD(glClear); + GLES2_LOAD(glClearColor); + GLES2_LOAD(glClearDepthf); GLES2_LOAD(glClearStencil); GLES2_LOAD(glColorMask); GLES2_LOAD(glCompileShader); @@ -247,6 +212,7 @@ static void __attribute__((constructor)) _init_androidglesv2() { GLES2_LOAD(glDeleteTextures); GLES2_LOAD(glDepthFunc); GLES2_LOAD(glDepthMask); + GLES2_LOAD(glDepthRangef); GLES2_LOAD(glDetachShader); GLES2_LOAD(glDisable); GLES2_LOAD(glDisableVertexAttribArray); @@ -298,11 +264,14 @@ static void __attribute__((constructor)) _init_androidglesv2() { 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); @@ -313,19 +282,24 @@ static void __attribute__((constructor)) _init_androidglesv2() { 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); @@ -334,984 +308,743 @@ static void __attribute__((constructor)) _init_androidglesv2() { 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); + } -static void glActiveTexture_wrapper(GLenum texture) + +void glActiveTexture (GLenum texture) { - return (*_glActiveTexture)(texture); + (*_glActiveTexture)(texture); } -static void glAttachShader_wrapper(GLuint program, GLuint shader) +void glAttachShader (GLuint program, GLuint shader) { - return (*_glAttachShader)(program, shader); + (*_glAttachShader)(program, shader); } -static void glBindAttribLocation_wrapper(GLuint program, GLuint index, const GLchar* name) +void glBindAttribLocation (GLuint program, GLuint index, const GLchar* name) { - return (*_glBindAttribLocation)(program, index, name); + (*_glBindAttribLocation)(program, index, name); } -static void glBindBuffer_wrapper(GLenum target, GLuint buffer) +void glBindBuffer (GLenum target, GLuint buffer) { - return (*_glBindBuffer)(target, buffer); + (*_glBindBuffer)(target, buffer); } -static void glBindFramebuffer_wrapper(GLenum target, GLuint framebuffer) +void glBindFramebuffer (GLenum target, GLuint framebuffer) { - return (*_glBindFramebuffer)(target, framebuffer); + (*_glBindFramebuffer)(target, framebuffer); } -static void glBindRenderbuffer_wrapper(GLenum target, GLuint framebuffer) +void glBindRenderbuffer (GLenum target, GLuint renderbuffer) { - return (*_glBindRenderbuffer)(target, framebuffer); + (*_glBindRenderbuffer)(target, renderbuffer); } -static void glBindTexture_wrapper(GLenum target, GLuint texture) +void glBindTexture (GLenum target, GLuint texture) { - return (*_glBindTexture)(target, texture); + (*_glBindTexture)(target, texture); } -static void glBlendEquation_wrapper(GLenum mode) +void glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { - return (*_glBlendEquation)(mode); + (*_glBlendColor)(red, green, blue, alpha); } -static void glBlendEquationSeparate_wrapper(GLenum modeRGB, GLenum modeAlpha) +void glBlendEquation ( GLenum mode ) { - return (*_glBlendEquationSeparate)(modeRGB, modeAlpha); + (*_glBlendEquation)(mode); } -static void glBlendFunc_wrapper(GLenum sfactor, GLenum dfactor) +void glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha) { - return (*_glBlendFunc)(sfactor, dfactor); + (*_glBlendEquationSeparate)(modeRGB, modeAlpha); } -static void glBlendFuncSeparate_wrapper(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +void glBlendFunc (GLenum sfactor, GLenum dfactor) { - return (*_glBlendFuncSeparate)(srcRGB, dstRGB, srcAlpha, dstAlpha); + (*_glBlendFunc)(sfactor, dfactor); } -static void glBufferData_wrapper(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) +void glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) { - return (*_glBufferData)(target, size, data, usage); + (*_glBlendFuncSeparate)(srcRGB, dstRGB, srcAlpha, dstAlpha); } -static void glBufferSubData_wrapper(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +void glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage) { - return (*_glBufferSubData)(target, offset, size, data); + (*_glBufferData)(target, size, data, usage); } -static GLenum glCheckFramebufferStatus_wrapper(GLenum target) +void glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data) +{ + (*_glBufferSubData)(target, offset, size, data); +} + +GLenum glCheckFramebufferStatus (GLenum target) { return (*_glCheckFramebufferStatus)(target); } -static void glClear_wrapper(GLbitfield mask) +void glClear (GLbitfield mask) +{ + (*_glClear)(mask); +} + +void glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { - return (*_glClear)(mask); + (*_glClearColor)(red, green, blue, alpha); } -static void glClearStencil_wrapper(GLint s) +void glClearDepthf (GLclampf depth) { - return (*_glClearStencil)(s); + (*_glClearDepthf)(depth); } -static void glColorMask_wrapper(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +void glClearStencil (GLint s) { - return (*_glColorMask)(red, green, blue, alpha); + (*_glClearStencil)(s); } -static void glCompileShader_wrapper(GLuint shader) +void glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { - return (*_glCompileShader)(shader); + (*_glColorMask)(red, green, blue, alpha); } -static void glCompressedTexImage2D_wrapper(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) +void glCompileShader (GLuint shader) { - return (*_glCompressedTexImage2D)(target, level, internalformat, width, height, border, imageSize, data); + (*_glCompileShader)(shader); } -static void glCompressedTexSubImage2D_wrapper(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) +void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) { - return (*_glCompressedTexSubImage2D)(target, level, xoffset, yoffset, width, height, format, imageSize, data); + (*_glCompressedTexImage2D)(target, level, internalformat, width, height, border, imageSize, data); } -static void glCopyTexImage2D_wrapper(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +void glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) { - return (*_glCopyTexImage2D)(target, level, internalformat, x, y, width, height, border); + (*_glCompressedTexSubImage2D)(target, level, xoffset, yoffset, width, height, format, imageSize, data); } -static void glCopyTexSubImage2D_wrapper(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +void glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { - return (*_glCopyTexSubImage2D)(target, level, xoffset, yoffset, x, y, width, height); + (*_glCopyTexImage2D)(target, level, internalformat, x, y, width, height, border); } -static GLuint glCreateProgram_wrapper(void) +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); +} + +GLuint glCreateProgram (void) { return (*_glCreateProgram)(); } -static GLuint glCreateShader_wrapper(GLenum type) +GLuint glCreateShader (GLenum type) { return (*_glCreateShader)(type); } -static void glCullFace_wrapper(GLenum mode) +void glCullFace (GLenum mode) +{ + (*_glCullFace)(mode); +} + +void glDeleteBuffers (GLsizei n, const GLuint* buffers) { - return (*_glCullFace)(mode); + (*_glDeleteBuffers)(n, buffers); } -static void glDeleteBuffers_wrapper(GLsizei n, const GLuint* buffers) +void glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers) { - return (*_glDeleteBuffers)(n, buffers); + (*_glDeleteFramebuffers)(n, framebuffers); } -static void glDeleteFramebuffers_wrapper(GLsizei n, const GLuint* buffers) +void glDeleteProgram (GLuint program) { - return (*_glDeleteFramebuffers)(n, buffers); + (*_glDeleteProgram)(program); } -static void glDeleteProgram_wrapper(GLuint program) +void glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers) { - return (*_glDeleteProgram)(program); + (*_glDeleteRenderbuffers)(n, renderbuffers); } -static void glDeleteRenderbuffers_wrapper(GLsizei n, const GLuint* renderbuffers) +void glDeleteShader (GLuint shader) { - return (*_glDeleteRenderbuffers)(n, renderbuffers); + (*_glDeleteShader)(shader); } -static void glDeleteShader_wrapper(GLuint shader) +void glDeleteTextures (GLsizei n, const GLuint* textures) { - return (*_glDeleteShader)(shader); + (*_glDeleteTextures)(n, textures); } -static void glDeleteTextures_wrapper(GLsizei n, const GLuint* textures) +void glDepthFunc (GLenum func) { - return (*_glDeleteTextures)(n, textures); + (*_glDepthFunc)(func); } -static void glDepthFunc_wrapper(GLenum func) +void glDepthMask (GLboolean flag) { - return (*_glDepthFunc)(func); + (*_glDepthMask)(flag); } -static void glDepthMask_wrapper(GLboolean flag) +void glDepthRangef (GLclampf zNear, GLclampf zFar) { - return (*_glDepthMask)(flag); + (*_glDepthRangef)(zNear, zFar); } -static void glDetachShader_wrapper(GLuint program, GLuint shader) +void glDetachShader (GLuint program, GLuint shader) { - return (*_glDetachShader)(program, shader); + (*_glDetachShader)(program, shader); } -static void glDisable_wrapper(GLenum cap) +void glDisable (GLenum cap) { - return (*_glDisable)(cap); + (*_glDisable)(cap); } -static void glDisableVertexAttribArray_wrapper(GLuint index) +void glDisableVertexAttribArray (GLuint index) { - return (*_glDisableVertexAttribArray)(index); + (*_glDisableVertexAttribArray)(index); } -static void glDrawArrays_wrapper(GLenum mode, GLint first, GLsizei count) +void glDrawArrays (GLenum mode, GLint first, GLsizei count) { - return (*_glDrawArrays)(mode, first, count); + (*_glDrawArrays)(mode, first, count); } -static void glDrawElements_wrapper(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) +void glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) { - return (*_glDrawElements)(mode, count, type, indices); + (*_glDrawElements)(mode, count, type, indices); } -static void glEnable_wrapper(GLenum cap) +void glEnable (GLenum cap) { - return (*_glEnable)(cap); + (*_glEnable)(cap); } -static void glEnableVertexAttribArray_wrapper(GLuint index) +void glEnableVertexAttribArray (GLuint index) { - return (*_glEnableVertexAttribArray)(index); + (*_glEnableVertexAttribArray)(index); } -static void glFinish_wrapper(void) +void glFinish (void) { - return (*_glFinish)(); + (*_glFinish)(); } -static void glFlush_wrapper(void) +void glFlush (void) { - return (*_glFlush)(); + (*_glFlush)(); } -static void glFramebufferRenderbuffer_wrapper(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +void glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { - return (*_glFramebufferRenderbuffer)(target, attachment, renderbuffertarget, renderbuffer); + (*_glFramebufferRenderbuffer)(target, attachment, renderbuffertarget, renderbuffer); } -static void glFramebufferTexture2D_wrapper(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +void glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { - return (*_glFramebufferTexture2D)(target, attachment, textarget, texture, level); + (*_glFramebufferTexture2D)(target, attachment, textarget, texture, level); } -static void glFrontFace_wrapper(GLenum mode) +void glFrontFace (GLenum mode) { - return (*_glFrontFace)(mode); + (*_glFrontFace)(mode); } -static void glGenBuffers_wrapper(GLsizei n, GLuint* buffers) +void glGenBuffers (GLsizei n, GLuint* buffers) { - return (*_glGenBuffers)(n, buffers); + (*_glGenBuffers)(n, buffers); } -static void glGenerateMipmap_wrapper(GLenum target) +void glGenerateMipmap (GLenum target) { - return (*_glGenerateMipmap)(target); + (*_glGenerateMipmap)(target); } -static void glGenFramebuffers_wrapper(GLsizei n, GLuint* framebuffers) +void glGenFramebuffers (GLsizei n, GLuint* framebuffers) { - return (*_glGenFramebuffers)(n, framebuffers); + (*_glGenFramebuffers)(n, framebuffers); } -static void glGenRenderbuffers_wrapper(GLsizei n, GLuint* renderbuffers) +void glGenRenderbuffers (GLsizei n, GLuint* renderbuffers) { - return (*_glGenRenderbuffers)(n, renderbuffers); + (*_glGenRenderbuffers)(n, renderbuffers); } -static void glGenTextures_wrapper(GLsizei n, GLuint* textures) +void glGenTextures (GLsizei n, GLuint* textures) { - return (*_glGenTextures)(n, textures); + (*_glGenTextures)(n, textures); } -static void glGetActiveAttrib_wrapper(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +void glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) { - return (*_glGetActiveAttrib)(program, index, bufsize, length, size, type, name); + (*_glGetActiveAttrib)(program, index, bufsize, length, size, type, name); } -static void glGetActiveUniform_wrapper(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) +void glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name) { - return (*_glGetActiveUniform)(program, index, bufsize, length, size, type, name); + (*_glGetActiveUniform)(program, index, bufsize, length, size, type, name); } -static void glGetAttachedShaders_wrapper(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +void glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) { - return (*_glGetAttachedShaders)(program, maxcount, count, shaders); + (*_glGetAttachedShaders)(program, maxcount, count, shaders); } -static int glGetAttribLocation_wrapper(GLuint program, const GLchar* name) +int glGetAttribLocation (GLuint program, const GLchar* name) { return (*_glGetAttribLocation)(program, name); } -static void glGetBooleanv_wrapper(GLenum pname, GLboolean* params) +void glGetBooleanv (GLenum pname, GLboolean* params) { - return (*_glGetBooleanv)(pname, params); + (*_glGetBooleanv)(pname, params); } -static void glGetBufferParameteriv_wrapper(GLenum target, GLenum pname, GLint* params) +void glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params) { - return (*_glGetBufferParameteriv)(target, pname, params); + (*_glGetBufferParameteriv)(target, pname, params); } -static GLenum glGetError_wrapper(void) +GLenum glGetError (void) { return (*_glGetError)(); } -static void glGetFloatv_wrapper(GLenum pname, GLfloat* params) +void glGetFloatv (GLenum pname, GLfloat* params) +{ + (*_glGetFloatv)(pname, params); +} + +void glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params) { - return (*_glGetFloatv)(pname, params); + (*_glGetFramebufferAttachmentParameteriv)(target, attachment, pname, params); } -static void glGetFramebufferAttachmentParameteriv_wrapper(GLenum target, GLenum attachment, GLenum pname, GLint* params) +void glGetIntegerv (GLenum pname, GLint* params) { - return (*_glGetFramebufferAttachmentParameteriv)(target, attachment, pname, params); + (*_glGetIntegerv)(pname, params); } -static void glGetIntegerv_wrapper(GLenum pname, GLint* params) +void glGetProgramiv (GLuint program, GLenum pname, GLint* params) { - return (*_glGetIntegerv)(pname, params); + (*_glGetProgramiv)(program, pname, params); } -static void glGetProgramiv_wrapper(GLuint program, GLenum pname, GLint* params) +void glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) { - return (*_glGetProgramiv)(program, pname, params); + (*_glGetProgramInfoLog)(program, bufsize, length, infolog); } -static void glGetProgramInfoLog_wrapper(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog) +void glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params) { - return (*_glGetProgramInfoLog)(program, bufsize, length, infolog); + (*_glGetRenderbufferParameteriv)(target, pname, params); } -static void glGetRenderbufferParameteriv_wrapper(GLenum target, GLenum pname, GLint* params) +void glGetShaderiv (GLuint shader, GLenum pname, GLint* params) { - return (*_glGetRenderbufferParameteriv)(target, pname, params); + (*_glGetShaderiv)(shader, pname, params); } -static void glGetShaderiv_wrapper(GLuint shader, GLenum pname, GLint* params) +void glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) { - return (*_glGetShaderiv)(shader, pname, params); + (*_glGetShaderInfoLog)(shader, bufsize, length, infolog); } -static void glGetShaderInfoLog_wrapper(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog) +void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { - return (*_glGetShaderInfoLog)(shader, bufsize, length, infolog); + (*_glGetShaderPrecisionFormat)(shadertype, precisiontype, range, precision); } -static void glGetShaderPrecisionFormat_wrapper(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +void glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) { - return (*_glGetShaderPrecisionFormat)(shadertype, precisiontype, range, precision); + (*_glGetShaderSource)(shader, bufsize, length, source); } -static void glGetShaderSource_wrapper(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source) +const GLubyte* glGetString (GLenum name) { - return (*_glGetShaderSource)(shader, bufsize, length, source); + // 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; + } + + return (*_glGetString)(name); } -static void glGetTexParameterfv_wrapper(GLenum target, GLenum pname, GLfloat* params) +void glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params) { - return (*_glGetTexParameterfv)(target, pname, params); + (*_glGetTexParameterfv)(target, pname, params); } -static void glGetTexParameteriv_wrapper(GLenum target, GLenum pname, GLint* params) +void glGetTexParameteriv (GLenum target, GLenum pname, GLint* params) { - return (*_glGetTexParameteriv)(target, pname, params); + (*_glGetTexParameteriv)(target, pname, params); } -static void glGetUniformfv_wrapper(GLuint program, GLint location, GLfloat* params) +void glGetUniformfv (GLuint program, GLint location, GLfloat* params) { - return (*_glGetUniformfv)(program, location, params); + (*_glGetUniformfv)(program, location, params); } -static void glGetUniformiv_wrapper(GLuint program, GLint location, GLint* params) +void glGetUniformiv (GLuint program, GLint location, GLint* params) { - return (*_glGetUniformiv)(program, location, params); + (*_glGetUniformiv)(program, location, params); } -static int glGetUniformLocation_wrapper(GLuint program, const GLchar* name) +int glGetUniformLocation (GLuint program, const GLchar* name) { return (*_glGetUniformLocation)(program, name); } -static void glGetVertexAttribfv_wrapper(GLuint index, GLenum pname, GLfloat* params) +void glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params) { - return (*_glGetVertexAttribfv)(index, pname, params); + (*_glGetVertexAttribfv)(index, pname, params); } -static void glGetVertexAttribiv_wrapper(GLuint index, GLenum pname, GLint* params) +void glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params) { - return (*_glGetVertexAttribiv)(index, pname, params); + (*_glGetVertexAttribiv)(index, pname, params); } -static void glGetVertexAttribPointerv_wrapper(GLuint index, GLenum pname, GLvoid** pointer) +void glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer) { - return (*_glGetVertexAttribPointerv)(index, pname, pointer); + (*_glGetVertexAttribPointerv)(index, pname, pointer); } -static void glHint_wrapper(GLenum target, GLenum mode) +void glHint (GLenum target, GLenum mode) { - return (*_glHint)(target, mode); + (*_glHint)(target, mode); } -static GLboolean glIsBuffer_wrapper(GLuint buffer) +GLboolean glIsBuffer (GLuint buffer) { return (*_glIsBuffer)(buffer); } -static GLboolean glIsEnabled_wrapper(GLenum cap) +GLboolean glIsEnabled (GLenum cap) { return (*_glIsEnabled)(cap); } -static GLboolean glIsFramebuffer_wrapper(GLuint framebuffer) +GLboolean glIsFramebuffer (GLuint framebuffer) { return (*_glIsFramebuffer)(framebuffer); } -static GLboolean glIsProgram_wrapper(GLuint program) +GLboolean glIsProgram (GLuint program) { return (*_glIsProgram)(program); } -static GLboolean glIsRenderbuffer_wrapper(GLuint renderbuffer) +GLboolean glIsRenderbuffer (GLuint renderbuffer) { return (*_glIsRenderbuffer)(renderbuffer); } -static GLboolean glIsShader_wrapper(GLuint shader) +GLboolean glIsShader (GLuint shader) { return (*_glIsShader)(shader); } -static GLboolean glIsTexture_wrapper(GLuint texture) +GLboolean glIsTexture (GLuint texture) { return (*_glIsTexture)(texture); } -static void glLinkProgram_wrapper(GLuint program) +void glLineWidth (GLfloat width) { - return (*_glLinkProgram)(program); + (*_glLineWidth)(width); } -static void glPixelStorei_wrapper(GLenum pname, GLint param) +void glLinkProgram (GLuint program) { - return (*_glPixelStorei)(pname, param); + (*_glLinkProgram)(program); } -static void glReadPixels_wrapper(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) +void glPixelStorei (GLenum pname, GLint param) { - return (*_glReadPixels)(x, y, width, height, format, type, pixels); + (*_glPixelStorei)(pname, param); } -static void glReleaseShaderCompiler_wrapper(void) +void glPolygonOffset (GLfloat factor, GLfloat units) { - return (*_glReleaseShaderCompiler)(); + (*_glPolygonOffset)(factor, units); } -static void glRenderbufferStorage_wrapper(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +void glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) { - return (*_glRenderbufferStorage)(target, internalformat, width, height); -} + (*_glReadPixels)(x, y, width, height, format, type, pixels); -static void glScissor_wrapper(GLint x, GLint y, GLsizei width, GLsizei height) -{ - return (*_glScissor)(x, y, width, height); } -static void glShaderBinary_wrapper(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) +void glReleaseShaderCompiler (void) { - return (*_glShaderBinary)(n, shaders, binaryformat, binary, length); + (*_glReleaseShaderCompiler)(); } -static void glShaderSource_wrapper(GLuint shader, GLsizei count, const GLchar** string, const GLint* length) +void glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { - return (*_glShaderSource)(shader, count, string, length); + (*_glRenderbufferStorage)(target, internalformat, width, height); } -static void glStencilFunc_wrapper(GLenum func, GLint ref, GLuint mask) +void glSampleCoverage (GLclampf value, GLboolean invert) { - return (*_glStencilFunc)(func, ref, mask); + (*_glSampleCoverage)(value, invert); } -static void glStencilFuncSeparate_wrapper(GLenum face, GLenum func, GLint ref, GLuint mask) +void glScissor (GLint x, GLint y, GLsizei width, GLsizei height) { - return (*_glStencilFuncSeparate)(face, func, ref, mask); + (*_glScissor)(x, y, width, height); } -static void glStencilMask_wrapper(GLuint mask) +void glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length) { - return (*_glStencilMask)(mask); + (*_glShaderBinary)(n, shaders, binaryformat, binary, length); } -static void glStencilMaskSeparate_wrapper(GLenum face, GLuint mask) +void glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length) { - return (*_glStencilMaskSeparate)(face, mask); + (*_glShaderSource)(shader, count, string, length); } -static void glStencilOp_wrapper(GLenum fail, GLenum zfail, GLenum zpass) +void glStencilFunc (GLenum func, GLint ref, GLuint mask) { - return (*_glStencilOp)(fail, zfail, zpass); + (*_glStencilFunc)(func, ref, mask); } -static void glStencilOpSeparate_wrapper(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +void glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask) { - return (*_glStencilOpSeparate)(face, fail, zfail, zpass); + (*_glStencilFuncSeparate)(face, func, ref, mask); } -static void glTexImage2D_wrapper(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) +void glStencilMask (GLuint mask) { - return (*_glTexImage2D)(target, level, internalformat, width, height, border, format, type, pixels); + (*_glStencilMask)(mask); } -static void glTexParameterfv_wrapper(GLenum target, GLenum pname, const GLfloat* params) +void glStencilMaskSeparate (GLenum face, GLuint mask) { - return (*_glTexParameterfv)(target, pname, params); + (*_glStencilMaskSeparate)(face, mask); } -static void glTexParameteri_wrapper(GLenum target, GLenum pname, GLint param) +void glStencilOp (GLenum fail, GLenum zfail, GLenum zpass) { - return (*_glTexParameteri)(target, pname, param); + (*_glStencilOp)(fail, zfail, zpass); } -static void glTexParameteriv_wrapper(GLenum target, GLenum pname, const GLint* params) +void glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { - return (*_glTexParameteriv)(target, pname, params); + (*_glStencilOpSeparate)(face, fail, zfail, zpass); } -static void glTexSubImage2D_wrapper(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) +void glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { - return (*_glTexSubImage2D)(target, level, xoffset, yoffset, width, height, format, type, pixels); + (*_glTexImage2D)(target, level, internalformat, width, height, border, format, type, pixels); } -static void glUniform1fv_wrapper(GLint location, GLsizei count, const GLfloat* v) +void glTexParameterf (GLenum target, GLenum pname, GLfloat param) { - return (*_glUniform1fv)(location, count, v); + (*_glTexParameterf)(target, pname, param); } -static void glUniform1i_wrapper(GLint location, GLint x) +void glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params) { - return (*_glUniform1i)(location, x); + (*_glTexParameterfv)(target, pname, params); } -static void glUniform1iv_wrapper(GLint location, GLsizei count, const GLint* v) +void glTexParameteri (GLenum target, GLenum pname, GLint param) { - return (*_glUniform1iv)(location, count, v); + (*_glTexParameteri)(target, pname, param); } -static void glUniform2fv_wrapper(GLint location, GLsizei count, const GLfloat* v) +void glTexParameteriv (GLenum target, GLenum pname, const GLint* params) { - return (*_glUniform2fv)(location, count, v); + (*_glTexParameteriv)(target, pname, params); } -static void glUniform2i_wrapper(GLint location, GLint x, GLint y) +void glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels) { - return (*_glUniform2i)(location, x, y); + (*_glTexSubImage2D)(target, level, xoffset, yoffset, width, height, format, type, pixels); } -static void glUniform2iv_wrapper(GLint location, GLsizei count, const GLint* v) +void glUniform1f (GLint location, GLfloat x) { - return (*_glUniform2iv)(location, count, v); + (*_glUniform1f)(location, x); } -static void glUniform3fv_wrapper(GLint location, GLsizei count, const GLfloat* v) +void glUniform1fv (GLint location, GLsizei count, const GLfloat* v) { - return (*_glUniform3fv)(location, count, v); + (*_glUniform1fv)(location, count, v); } -static void glUniform3i_wrapper(GLint location, GLint x, GLint y, GLint z) +void glUniform1i (GLint location, GLint x) { - return (*_glUniform3i)(location, x, y, z); + (*_glUniform1i)(location, x); } -static void glUniform3iv_wrapper(GLint location, GLsizei count, const GLint* v) +void glUniform1iv (GLint location, GLsizei count, const GLint* v) { - return (*_glUniform3iv)(location, count, v); + (*_glUniform1iv)(location, count, v); } -static void glUniform4fv_wrapper(GLint location, GLsizei count, const GLfloat* v) +void glUniform2f (GLint location, GLfloat x, GLfloat y) { - return (*_glUniform4fv)(location, count, v); + (*_glUniform2f)(location, x, y); } -static void glUniform4i_wrapper(GLint location, GLint x, GLint y, GLint z, GLint w) +void glUniform2fv (GLint location, GLsizei count, const GLfloat* v) { - return (*_glUniform4i)(location, x, y, z, w); + (*_glUniform2fv)(location, count, v); } -static void glUniform4iv_wrapper(GLint location, GLsizei count, const GLint* v) +void glUniform2i (GLint location, GLint x, GLint y) { - return (*_glUniform4iv)(location, count, v); + (*_glUniform2i)(location, x, y); } -static void glUniformMatrix2fv_wrapper(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void glUniform2iv (GLint location, GLsizei count, const GLint* v) { - return (*_glUniformMatrix2fv)(location, count, transpose, value); + (*_glUniform2iv)(location, count, v); } -static void glUniformMatrix3fv_wrapper(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z) { - return (*_glUniformMatrix3fv)(location, count, transpose, value); + (*_glUniform3f)(location, x, y, z); } -static void glUniformMatrix4fv_wrapper(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +void glUniform3fv (GLint location, GLsizei count, const GLfloat* v) { - return (*_glUniformMatrix4fv)(location, count, transpose, value); + (*_glUniform3fv)(location, count, v); } -static void glUseProgram_wrapper(GLuint program) +void glUniform3i (GLint location, GLint x, GLint y, GLint z) { - return (*_glUseProgram)(program); + (*_glUniform3i)(location, x, y, z); } -static void glValidateProgram_wrapper(GLuint program) +void glUniform3iv (GLint location, GLsizei count, const GLint* v) { - return (*_glValidateProgram)(program); + (*_glUniform3iv)(location, count, v); } -static void glVertexAttrib1fv_wrapper(GLuint indx, const GLfloat* values) +void glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { - return (*_glVertexAttrib1fv)(indx, values); + (*_glUniform4f)(location, x, y, z, w); } -static void glVertexAttrib2fv_wrapper(GLuint indx, const GLfloat* values) +void glUniform4fv (GLint location, GLsizei count, const GLfloat* v) { - return (*_glVertexAttrib2fv)(indx, values); + (*_glUniform4fv)(location, count, v); } -static void glVertexAttrib3fv_wrapper(GLuint indx, const GLfloat* values) +void glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w) { - return (*_glVertexAttrib3fv)(indx, values); + (*_glUniform4i)(location, x, y, z, w); } -static void glVertexAttrib4fv_wrapper(GLuint indx, const GLfloat* values) +void glUniform4iv (GLint location, GLsizei count, const GLint* v) { - return (*_glVertexAttrib4fv)(indx, values); + (*_glUniform4iv)(location, count, v); } -static void glVertexAttribPointer_wrapper(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) +void glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - return (*_glVertexAttribPointer)(indx, size, type, normalized, stride, ptr); + (*_glUniformMatrix2fv)(location, count, transpose, value); } -static void glViewport_wrapper(GLint x, GLint y, GLsizei width, GLsizei height) +void glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - return (*_glViewport)(x, y, width, height); + (*_glUniformMatrix3fv)(location, count, transpose, value); } - - -GLES2_IDLOAD(glActiveTexture); - -GLES2_IDLOAD(glAttachShader); - -GLES2_IDLOAD(glBindAttribLocation); - -GLES2_IDLOAD(glBindBuffer); - -GLES2_IDLOAD(glBindFramebuffer); - -GLES2_IDLOAD(glBindRenderbuffer); - -GLES2_IDLOAD(glBindTexture); - -GLES2_IDLOAD(glBlendEquation); - -GLES2_IDLOAD(glBlendEquationSeparate); - -GLES2_IDLOAD(glBlendFunc); - -GLES2_IDLOAD(glBlendFuncSeparate); - -GLES2_IDLOAD(glBufferData); - -GLES2_IDLOAD(glBufferSubData); - -GLES2_IDLOAD(glCheckFramebufferStatus); - -GLES2_IDLOAD(glClear); - -GLES2_IDLOAD(glClearStencil); - -GLES2_IDLOAD(glColorMask); - -GLES2_IDLOAD(glCompileShader); - -GLES2_IDLOAD(glCompressedTexImage2D); - -GLES2_IDLOAD(glCompressedTexSubImage2D); - -GLES2_IDLOAD(glCopyTexImage2D); - -GLES2_IDLOAD(glCopyTexSubImage2D); - -GLES2_IDLOAD(glCreateProgram); - -GLES2_IDLOAD(glCreateShader); - -GLES2_IDLOAD(glCullFace); - -GLES2_IDLOAD(glDeleteBuffers); - -GLES2_IDLOAD(glDeleteFramebuffers); - -GLES2_IDLOAD(glDeleteProgram); - -GLES2_IDLOAD(glDeleteRenderbuffers); - -GLES2_IDLOAD(glDeleteShader); - -GLES2_IDLOAD(glDeleteTextures); - -GLES2_IDLOAD(glDepthFunc); - -GLES2_IDLOAD(glDepthMask); - -GLES2_IDLOAD(glDetachShader); - -GLES2_IDLOAD(glDisable); - -GLES2_IDLOAD(glDisableVertexAttribArray); - -GLES2_IDLOAD(glDrawArrays); - -GLES2_IDLOAD(glDrawElements); - -GLES2_IDLOAD(glEnable); - -GLES2_IDLOAD(glEnableVertexAttribArray); - -GLES2_IDLOAD(glFinish); - -GLES2_IDLOAD(glFlush); - -GLES2_IDLOAD(glFramebufferRenderbuffer); - -GLES2_IDLOAD(glFramebufferTexture2D); - -GLES2_IDLOAD(glFrontFace); - -GLES2_IDLOAD(glGenBuffers); - -GLES2_IDLOAD(glGenerateMipmap); - -GLES2_IDLOAD(glGenFramebuffers); - -GLES2_IDLOAD(glGenRenderbuffers); - -GLES2_IDLOAD(glGenTextures); - -GLES2_IDLOAD(glGetActiveAttrib); - -GLES2_IDLOAD(glGetActiveUniform); - -GLES2_IDLOAD(glGetAttachedShaders); - -GLES2_IDLOAD(glGetAttribLocation); - -GLES2_IDLOAD(glGetBooleanv); - -GLES2_IDLOAD(glGetBufferParameteriv); - -GLES2_IDLOAD(glGetError); - -GLES2_IDLOAD(glGetFloatv); - -GLES2_IDLOAD(glGetFramebufferAttachmentParameteriv); - -GLES2_IDLOAD(glGetIntegerv); - -GLES2_IDLOAD(glGetProgramiv); - -GLES2_IDLOAD(glGetProgramInfoLog); - -GLES2_IDLOAD(glGetRenderbufferParameteriv); - -GLES2_IDLOAD(glGetShaderiv); - -GLES2_IDLOAD(glGetShaderInfoLog); - -GLES2_IDLOAD(glGetShaderPrecisionFormat); - -GLES2_IDLOAD(glGetShaderSource); - -GLES2_IDLOAD(glGetTexParameterfv); - -GLES2_IDLOAD(glGetTexParameteriv); - -GLES2_IDLOAD(glGetUniformfv); - -GLES2_IDLOAD(glGetUniformiv); - -GLES2_IDLOAD(glGetUniformLocation); - -GLES2_IDLOAD(glGetVertexAttribfv); - -GLES2_IDLOAD(glGetVertexAttribiv); - -GLES2_IDLOAD(glGetVertexAttribPointerv); - -GLES2_IDLOAD(glHint); - -GLES2_IDLOAD(glIsBuffer); - -GLES2_IDLOAD(glIsEnabled); - -GLES2_IDLOAD(glIsFramebuffer); - -GLES2_IDLOAD(glIsProgram); - -GLES2_IDLOAD(glIsRenderbuffer); - -GLES2_IDLOAD(glIsShader); - -GLES2_IDLOAD(glIsTexture); - -GLES2_IDLOAD(glLinkProgram); - -GLES2_IDLOAD(glPixelStorei); - -GLES2_IDLOAD(glReadPixels); - -GLES2_IDLOAD(glReleaseShaderCompiler); - -GLES2_IDLOAD(glRenderbufferStorage); - -GLES2_IDLOAD(glScissor); - -GLES2_IDLOAD(glShaderBinary); - -GLES2_IDLOAD(glShaderSource); - -GLES2_IDLOAD(glStencilFunc); - -GLES2_IDLOAD(glStencilFuncSeparate); - -GLES2_IDLOAD(glStencilMask); - -GLES2_IDLOAD(glStencilMaskSeparate); - -GLES2_IDLOAD(glStencilOp); - -GLES2_IDLOAD(glStencilOpSeparate); - -GLES2_IDLOAD(glTexImage2D); - -GLES2_IDLOAD(glTexParameterfv); - -GLES2_IDLOAD(glTexParameteri); - -GLES2_IDLOAD(glTexParameteriv); - -GLES2_IDLOAD(glTexSubImage2D); - -GLES2_IDLOAD(glUniform1fv); - -GLES2_IDLOAD(glUniform1i); - -GLES2_IDLOAD(glUniform1iv); - -GLES2_IDLOAD(glUniform2fv); - -GLES2_IDLOAD(glUniform2i); - -GLES2_IDLOAD(glUniform2iv); - -GLES2_IDLOAD(glUniform3fv); - -GLES2_IDLOAD(glUniform3i); - -GLES2_IDLOAD(glUniform3iv); - -GLES2_IDLOAD(glUniform4fv); - -GLES2_IDLOAD(glUniform4i); - -GLES2_IDLOAD(glUniform4iv); - -GLES2_IDLOAD(glUniformMatrix2fv); - -GLES2_IDLOAD(glUniformMatrix3fv); - -GLES2_IDLOAD(glUniformMatrix4fv); - -GLES2_IDLOAD(glUseProgram); - -GLES2_IDLOAD(glValidateProgram); - -GLES2_IDLOAD(glVertexAttrib1fv); - -GLES2_IDLOAD(glVertexAttrib2fv); - -GLES2_IDLOAD(glVertexAttrib3fv); - -GLES2_IDLOAD(glVertexAttrib4fv); - -GLES2_IDLOAD(glVertexAttribPointer); - -GLES2_IDLOAD(glViewport); - -void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) +void glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { - struct egl_image *img = image; - return (*_glEGLImageTargetTexture2DOES)(target, img ? img->egl_image : NULL); + (*_glUniformMatrix4fv)(location, count, transpose, value); } -void glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +void glUseProgram (GLuint program) { - return (*_glBlendColor)(red, green, blue, alpha); + (*_glUseProgram)(program); } -void glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +void glValidateProgram (GLuint program) { - return (*_glVertexAttrib4f)(indx, x, y, z, w); + (*_glValidateProgram)(program); } -void glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y) +void glVertexAttrib1f (GLuint indx, GLfloat x) { - return (*_glVertexAttrib2f)(indx, x, y); + (*_glVertexAttrib1f)(indx, x); } -void glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z) +void glVertexAttrib1fv (GLuint indx, const GLfloat* values) { - return (*_glVertexAttrib3f)(indx, x, y, z); + (*_glVertexAttrib1fv)(indx, values); } - -void glVertexAttrib1f (GLuint indx, GLfloat x) +void glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y) { - return (*_glVertexAttrib1f)(indx, x); + (*_glVertexAttrib2f)(indx, x, y); } -void glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +void glVertexAttrib2fv (GLuint indx, const GLfloat* values) { - return (*_glUniform4f)(location, x, y, z, w); + (*_glVertexAttrib2fv)(indx, values); } -void glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z) +void glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z) { - return (*_glUniform3f)(location, x, y, z); + (*_glVertexAttrib3f)(indx, x, y, z); } -void glUniform2f (GLint location, GLfloat x, GLfloat y) +void glVertexAttrib3fv (GLuint indx, const GLfloat* values) { - return (*_glUniform2f)(location, x, y); + (*_glVertexAttrib3fv)(indx, values); } -void glUniform1f (GLint location, GLfloat x) +void glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { - return (*_glUniform1f)(location, x); + (*_glVertexAttrib4f)(indx, x, y, z, w); } -void glTexParameterf (GLenum target, GLenum pname, GLfloat param) +void glVertexAttrib4fv (GLuint indx, const GLfloat* values) { - return (*_glTexParameterf)(target, pname, param); + (*_glVertexAttrib4fv)(indx, values); } -void glSampleCoverage (GLclampf value, GLboolean invert) +void glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) { - return (*_glSampleCoverage)(value, invert); -} -void glPolygonOffset (GLfloat factor, GLfloat units) -{ - return (*_glPolygonOffset)(factor, units); -} -void glDepthRangef (GLclampf zNear, GLclampf zFar) -{ - return (*_glDepthRangef)(zNear, zFar); + (*_glVertexAttribPointer)(indx, size, type, normalized, stride, ptr); } - -void glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +void glViewport (GLint x, GLint y, GLsizei width, GLsizei height) { - return (*_glClearColor)(red, green, blue, alpha); + (*_glViewport)(x, y, width, height); } -void glClearDepthf (GLclampf depth) -{ - return (*_glClearDepthf)(depth); -} -void glLineWidth (GLfloat width) +void glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image) { - return (*_glLineWidth)(width); + (*_glEGLImageTargetTexture2DOES)(target, image); } -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(glGetString_versionString, sizeof(glGetString_versionString), "OpenGL ES 2.0 (%s)", (*_glGetString)(name)); - return glGetString_versionString; - } - return (*_glGetString)(name); -} + diff --git a/hybris/hardware/hardware.c b/hybris/hardware/hardware.c index 84ac2b9b6..74b6b20c2 100644 --- a/hybris/hardware/hardware.c +++ b/hybris/hardware/hardware.c @@ -17,6 +17,7 @@ #include #include +#include #include #include diff --git a/hybris/include/Makefile.am b/hybris/include/Makefile.am index b27e549a3..4921dae43 100644 --- a/hybris/include/Makefile.am +++ b/hybris/include/Makefile.am @@ -65,6 +65,20 @@ propertiesincludedir = $(includedir)/hybris/properties 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/common commoninclude_HEADERS = \ hybris/common/binding.h \ hybris/common/floating_point_abi.h \ - hybris/common/dlfcn.h + hybris/common/dlfcn.h \ + hybris/common/hooks.h diff --git a/hybris/include/hybris/camera/camera_compatibility_layer.h b/hybris/include/hybris/camera/camera_compatibility_layer.h index 72aabcfa4..90f12a0b5 100644 --- a/hybris/include/hybris/camera/camera_compatibility_layer.h +++ b/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 diff --git a/hybris/include/hybris/camera/camera_compatibility_layer_capabilities.h b/hybris/include/hybris/camera/camera_compatibility_layer_capabilities.h index 985f67d20..cc7453e1c 100644 --- a/hybris/include/hybris/camera/camera_compatibility_layer_capabilities.h +++ b/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); diff --git a/hybris/include/hybris/camera/camera_compatibility_layer_configuration_translator.h b/hybris/include/hybris/camera/camera_compatibility_layer_configuration_translator.h index fac5e2496..ed80d4de1 100644 --- a/hybris/include/hybris/camera/camera_compatibility_layer_configuration_translator.h +++ b/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 init_scene_modes_lut() + static android::DefaultKeyedVector init_scene_modes_lut() { - android::KeyedVector m; + android::DefaultKeyedVector 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 scene_modes_lut = init_scene_modes_lut(); + static android::DefaultKeyedVector scene_modes_lut = init_scene_modes_lut(); static const char* auto_focus_modes[] = { diff --git a/hybris/include/hybris/common/binding.h b/hybris/include/hybris/common/binding.h index 779e45cb9..4900b9065 100644 --- a/hybris/include/hybris/common/binding.h +++ b/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, void *info); * 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, void *info); 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, void *info); * 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. diff --git a/hybris/common/dlfcn.c b/hybris/include/hybris/common/hooks.h similarity index 60% rename from hybris/common/dlfcn.c rename to hybris/include/hybris/common/hooks.h index fd79862e8..e78d7d561 100644 --- a/hybris/common/dlfcn.c +++ b/hybris/include/hybris/common/hooks.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Intel Corporation + * 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. @@ -15,30 +15,22 @@ * */ +#ifndef _HYBRIS_HOOKS_H_ +#define _HYBRIS_HOOKS_H_ + #include #include -void *hybris_dlopen(const char *filename, int flag) -{ - return android_dlopen(filename,flag); -} - +#ifdef __cplusplus +extern "C" { +#endif -void *hybris_dlsym(void *handle, const char *symbol) -{ - return android_dlsym(handle,symbol); -} - - -int hybris_dlclose(void *handle) -{ - return android_dlclose(handle); -} +typedef void* (*hybris_hook_cb)(const char *symbol_name, const char *requester); +void hybris_set_hook_callback(hybris_hook_cb callback); -const char *hybris_dlerror(void) -{ - return android_dlerror(); +#ifdef __cplusplus } +#endif -// vim: noai:ts=4:sw=4:ss=4:expandtab +#endif diff --git a/hybris/include/hybris/input/input_stack_compatibility_layer.h b/hybris/include/hybris/input/input_stack_compatibility_layer.h index e0dc8bccd..1b14e96cc 100644 --- a/hybris/include/hybris/input/input_stack_compatibility_layer.h +++ b/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); diff --git a/hybris/include/hybris/internal/camera_control.h b/hybris/include/hybris/internal/camera_control.h index 697d6eee0..2ea1bb98e 100644 --- a/hybris/include/hybris/internal/camera_control.h +++ b/hybris/include/hybris/internal/camera_control.h @@ -19,7 +19,11 @@ #include #include +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 #include +#else +#include +#endif #include #include @@ -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 camera; android::CameraParameters camera_parameters; +#if ANDROID_VERSION_MAJOR==4 && ANDROID_VERSION_MINOR<=2 android::sp preview_texture; - - // From android::SurfaceTexture::FrameAvailableListener +#else + android::sp 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); diff --git a/hybris/include/hybris/internal/surface_flinger_compatibility_layer_internal.h b/hybris/include/hybris/internal/surface_flinger_compatibility_layer_internal.h index c0717787c..f784ca80a 100644 --- a/hybris/include/hybris/internal/surface_flinger_compatibility_layer_internal.h +++ b/hybris/include/hybris/internal/surface_flinger_compatibility_layer_internal.h @@ -25,6 +25,7 @@ #include +#include #include #include #include diff --git a/hybris/include/hybris/media/decoding_service.h b/hybris/include/hybris/media/decoding_service.h new file mode 100644 index 000000000..26e15cf67 --- /dev/null +++ b/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 + */ + +#ifndef DECODING_SERVICE_H_ +#define DECODING_SERVICE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +// 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 diff --git a/hybris/include/hybris/media/media_buffer_layer.h b/hybris/include/hybris/media/media_buffer_layer.h new file mode 100644 index 000000000..580d1840e --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_BUFFER_LAYER_H_ +#define MEDIA_BUFFER_LAYER_H_ + +#include +#include + +#include +#include + +#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 diff --git a/hybris/include/hybris/media/media_codec_layer.h b/hybris/include/hybris/media/media_codec_layer.h new file mode 100644 index 000000000..d38d9c5e1 --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_CODEC_LAYER_H_ +#define MEDIA_CODEC_LAYER_H_ + +#include +#include + +#ifdef SIMPLE_PLAYER +#include +#endif + +#include +#include +#include +#include + +#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_ diff --git a/hybris/include/hybris/media/media_codec_list.h b/hybris/include/hybris/media/media_codec_list.h new file mode 100644 index 000000000..b5e0c9575 --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_CODEC_LIST_PRIV_H_ +#define MEDIA_CODEC_LIST_PRIV_H_ + +#include +#include +#include + +#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_ diff --git a/hybris/include/hybris/media/media_codec_source_layer.h b/hybris/include/hybris/media/media_codec_source_layer.h new file mode 100644 index 000000000..cd23e3b0d --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_CODEC_SOURCE_LAYER_H_ +#define MEDIA_CODEC_SOURCE_LAYER_H_ + +#include + +#include +#include +#include +#include + +#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 diff --git a/hybris/include/hybris/media/media_compatibility_layer.h b/hybris/include/hybris/media/media_compatibility_layer.h new file mode 100644 index 000000000..fed15dfac --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_COMPATIBILITY_LAYER_H_ +#define MEDIA_COMPATIBILITY_LAYER_H_ + +#include +#include +#include + +#include + +#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_ diff --git a/hybris/include/hybris/media/media_format_layer.h b/hybris/include/hybris/media/media_format_layer.h new file mode 100644 index 000000000..4ea80add8 --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_FORMAT_LAYER_H_ +#define MEDIA_FORMAT_LAYER_H_ + +#include +#include + +#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_ diff --git a/hybris/include/hybris/media/media_message_layer.h b/hybris/include/hybris/media/media_message_layer.h new file mode 100644 index 000000000..d09788b50 --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_MESSAGE_LAYER_H_ +#define MEDIA_MESSAGE_LAYER_H_ + +#include + +#include +#include +#include + +#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 diff --git a/hybris/include/hybris/media/media_meta_data_layer.h b/hybris/include/hybris/media/media_meta_data_layer.h new file mode 100644 index 000000000..99ac70c09 --- /dev/null +++ b/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 + */ + +#ifndef MEDIA_META_DATA_LAYER_H_ +#define MEDIA_META_DATA_LAYER_H_ + +#include + +#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 diff --git a/hybris/include/hybris/media/media_recorder_layer.h b/hybris/include/hybris/media/media_recorder_layer.h new file mode 100644 index 000000000..e890b6bc0 --- /dev/null +++ b/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 +#include +#include +#include + +#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 diff --git a/hybris/include/hybris/media/recorder_compatibility_layer.h b/hybris/include/hybris/media/recorder_compatibility_layer.h new file mode 100644 index 000000000..8ba9b3ac2 --- /dev/null +++ b/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 +#include +#include +#include + +#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 diff --git a/hybris/include/hybris/media/surface_texture_client_hybris.h b/hybris/include/hybris/media/surface_texture_client_hybris.h new file mode 100644 index 000000000..e793df0b1 --- /dev/null +++ b/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 + */ + +#ifndef SURFACE_TEXTURE_CLIENT_HYBRIS_H_ +#define SURFACE_TEXTURE_CLIENT_HYBRIS_H_ + +#include +#include + +#include + +#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_ diff --git a/hybris/include/hybris/ui/ui_compatibility_layer.h b/hybris/include/hybris/ui/ui_compatibility_layer.h index af504c3e6..d80d276cb 100644 --- a/hybris/include/hybris/ui/ui_compatibility_layer.h +++ b/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); diff --git a/hybris/input/Makefile.am b/hybris/input/Makefile.am new file mode 100644 index 000000000..0d823c943 --- /dev/null +++ b/hybris/input/Makefile.am @@ -0,0 +1,17 @@ +lib_LTLIBRARIES = \ + libis.la + +libis_la_SOURCES = is.c +libis_la_CFLAGS = -I$(top_srcdir)/include $(ANDROID_HEADERS_CFLAGS) +if WANT_TRACE +libis_la_CFLAGS += -DDEBUG +endif +if WANT_DEBUG +libis_la_CFLAGS += -ggdb -O0 +endif +libis_la_LDFLAGS = \ + $(top_builddir)/common/libhybris-common.la \ + -version-info "1":"0":"0" + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libis.pc diff --git a/hybris/input/is.c b/hybris/input/is.c new file mode 100644 index 000000000..0b3da08bd --- /dev/null +++ b/hybris/input/is.c @@ -0,0 +1,44 @@ +/* + * 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: Michael Frey + * Ricardo Salveti de Araujo + */ + +#include +#include +#include + +#include +#include + +#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); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(is, android_input_stack_start_waiting_for_flag, bool*); +HYBRIS_IMPLEMENT_VOID_FUNCTION0(is, android_input_stack_stop); +HYBRIS_IMPLEMENT_VOID_FUNCTION0(is, android_input_stack_shutdown); diff --git a/hybris/input/libis.pc.in b/hybris/input/libis.pc.in new file mode 100644 index 000000000..c2c20a838 --- /dev/null +++ b/hybris/input/libis.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=@libdir@ +includedir=@includedir@ + +Name: hybris-input +Description: libhybris input library +Version: @VERSION@ +Libs: -L${libdir} -lhybris-common -lis +Cflags: -I${includedir} diff --git a/hybris/libnfc_ndef_nxp/Makefile.am b/hybris/libnfc_ndef_nxp/Makefile.am index 1427cf85e..9255e9e03 100644 --- a/hybris/libnfc_ndef_nxp/Makefile.am +++ b/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 diff --git a/hybris/libnfc_ndef_nxp/libnfc_ndef_nxp.c b/hybris/libnfc_ndef_nxp/libnfc_ndef_nxp.c index 5af8393a9..0b80bb95e 100644 --- a/hybris/libnfc_ndef_nxp/libnfc_ndef_nxp.c +++ b/hybris/libnfc_ndef_nxp/libnfc_ndef_nxp.c @@ -34,7 +34,7 @@ #include -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 *); diff --git a/hybris/libnfc_nxp/Makefile.am b/hybris/libnfc_nxp/Makefile.am index 436c6d519..b053f4947 100644 --- a/hybris/libnfc_nxp/Makefile.am +++ b/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 diff --git a/hybris/libnfc_nxp/libnfc_nxp.c b/hybris/libnfc_nxp/libnfc_nxp.c index d8e85f083..f58073c31 100644 --- a/hybris/libnfc_nxp/libnfc_nxp.c +++ b/hybris/libnfc_nxp/libnfc_nxp.c @@ -56,7 +56,7 @@ typedef void (*pphDal4Nfc_DeferFuncPointer_t) (void * ); #include -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 **); diff --git a/hybris/libsync/sync.c b/hybris/libsync/sync.c index 398321469..a1a409f4f 100644 --- a/hybris/libsync/sync.c +++ b/hybris/libsync/sync.c @@ -28,6 +28,8 @@ #include #include +extern size_t strlcpy(char *dst, const char *src, size_t siz); + int sync_wait(int fd, int timeout) { __s32 to = timeout; diff --git a/hybris/media/Makefile.am b/hybris/media/Makefile.am new file mode 100644 index 000000000..62476a43b --- /dev/null +++ b/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 diff --git a/hybris/media/libmedia.pc.in b/hybris/media/libmedia.pc.in new file mode 100644 index 000000000..336a6a94c --- /dev/null +++ b/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} diff --git a/hybris/media/media.c b/hybris/media/media.c new file mode 100644 index 000000000..d39c45491 --- /dev/null +++ b/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 + * Ricardo Salveti de Araujo + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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*); diff --git a/hybris/properties/cache.c b/hybris/properties/cache.c index 72472b479..019b7db80 100644 --- a/hybris/properties/cache.c +++ b/hybris/properties/cache.c @@ -75,7 +75,6 @@ char *hybris_propcache_find(const char *key) if (prop) return prop->value; -out: return ret; } @@ -99,7 +98,6 @@ static void cache_update() { struct stat st; FILE *f = fopen("/system/build.prop", "r"); - char *ret = NULL; if (!f) return; diff --git a/hybris/properties/properties.c b/hybris/properties/properties.c index 8466d68e5..55cdda628 100644 --- a/hybris/properties/properties.c +++ b/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. diff --git a/hybris/sf/Makefile.am b/hybris/sf/Makefile.am new file mode 100644 index 000000000..13d5a8618 --- /dev/null +++ b/hybris/sf/Makefile.am @@ -0,0 +1,17 @@ +lib_LTLIBRARIES = \ + libsf.la + +libsf_la_SOURCES = sf.c +libsf_la_CFLAGS = -I$(top_srcdir)/include $(ANDROID_HEADERS_CFLAGS) +if WANT_TRACE +libsf_la_CFLAGS += -DDEBUG +endif +if WANT_DEBUG +libsf_la_CFLAGS += -ggdb -O0 +endif +libsf_la_LDFLAGS = \ + $(top_builddir)/common/libhybris-common.la \ + -version-info "1":"0":"0" + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libsf.pc diff --git a/hybris/sf/libsf.pc.in b/hybris/sf/libsf.pc.in new file mode 100644 index 000000000..1d1652e55 --- /dev/null +++ b/hybris/sf/libsf.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=@libdir@ +includedir=@includedir@ + +Name: hybris-surface-flinger +Description: libhybris surface flinger library +Version: @VERSION@ +Libs: -L${libdir} -lhybris-common -lsf +Cflags: -I${includedir} diff --git a/hybris/sf/sf.c b/hybris/sf/sf.c new file mode 100644 index 000000000..45258cc17 --- /dev/null +++ b/hybris/sf/sf.c @@ -0,0 +1,59 @@ +/* + * 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: Michael Frey + * Ricardo Salveti de Araujo + */ + +#include +#include +#include + +#include +#include + +#define COMPAT_LIBRARY_PATH "libsf_compat_layer.so" + +HYBRIS_LIBRARY_INITIALIZE(sf, COMPAT_LIBRARY_PATH); + +HYBRIS_IMPLEMENT_VOID_FUNCTION1(sf, sf_blank, size_t); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(sf, sf_unblank, size_t); +HYBRIS_IMPLEMENT_FUNCTION1(sf, size_t, sf_get_display_width, size_t); +HYBRIS_IMPLEMENT_FUNCTION1(sf, size_t, sf_get_display_height, size_t); +HYBRIS_IMPLEMENT_FUNCTION1(sf, struct SfClient*, sf_client_create_full, int); +HYBRIS_IMPLEMENT_FUNCTION0(sf, struct SfClient*, sf_client_create); +HYBRIS_IMPLEMENT_FUNCTION1(sf, EGLDisplay, sf_client_get_egl_display, + struct SfClient*); +HYBRIS_IMPLEMENT_FUNCTION1(sf, EGLConfig, sf_client_get_egl_config, + struct SfClient*); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(sf, sf_client_begin_transaction, + struct SfClient*); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(sf, sf_client_end_transaction, + struct SfClient*); +HYBRIS_IMPLEMENT_FUNCTION2(sf, struct SfSurface*, sf_surface_create, + struct SfClient*, SfSurfaceCreationParameters*); +HYBRIS_IMPLEMENT_FUNCTION1(sf, EGLSurface, sf_surface_get_egl_surface, + struct SfSurface*); +HYBRIS_IMPLEMENT_FUNCTION1(sf, EGLNativeWindowType, + sf_surface_get_egl_native_window, struct SfSurface*); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(sf, sf_surface_make_current, struct SfSurface*); +HYBRIS_IMPLEMENT_VOID_FUNCTION3(sf, sf_surface_move_to, + struct SfSurface*, int, int); +HYBRIS_IMPLEMENT_VOID_FUNCTION3(sf, sf_surface_set_size, + struct SfSurface*, int, int); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(sf, sf_surface_set_layer, + struct SfSurface*, int); +HYBRIS_IMPLEMENT_VOID_FUNCTION2(sf, sf_surface_set_alpha, + struct SfSurface*, float); diff --git a/hybris/tests/Makefile.am b/hybris/tests/Makefile.am index 7b5ac8841..524cb619a 100644 --- a/hybris/tests/Makefile.am +++ b/hybris/tests/Makefile.am @@ -1,10 +1,17 @@ bin_PROGRAMS = \ + test_audio \ test_egl \ test_egl_configs \ test_glesv2 \ 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 @@ -34,7 +41,8 @@ endif bin_PROGRAMS += test_audio 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 @@ -112,8 +120,68 @@ test_lights_LDADD = \ $(top_builddir)/common/libhybris-common.la \ $(top_builddir)/hardware/libhardware.la +test_ui_SOURCES = test_ui.c +test_ui_CFLAGS = \ + -I$(top_srcdir)/include \ + $(ANDROID_HEADERS_CFLAGS) +test_ui_LDADD = \ + $(top_builddir)/common/libhybris-common.la \ + $(top_builddir)/ui/libui.la + +test_sf_SOURCES = test_sf.c +test_sf_CFLAGS = \ + -I$(top_srcdir)/include \ + $(ANDROID_HEADERS_CFLAGS) +test_sf_LDADD = \ + $(top_builddir)/common/libhybris-common.la \ + $(top_builddir)/egl/libEGL.la \ + $(top_builddir)/glesv2/libGLESv2.la \ + $(top_builddir)/sf/libsf.la + +test_input_SOURCES = test_input.c +test_input_CFLAGS = \ + -I$(top_srcdir)/include \ + $(ANDROID_HEADERS_CFLAGS) +test_input_LDADD = \ + $(top_builddir)/common/libhybris-common.la \ + $(top_builddir)/input/libis.la + +test_camera_SOURCES = test_camera.c +test_camera_CFLAGS = \ + -I$(top_srcdir)/include \ + $(ANDROID_HEADERS_CFLAGS) + +test_camera_LDADD = \ + $(top_builddir)/common/libhybris-common.la \ + $(top_builddir)/egl/libEGL.la \ + $(top_builddir)/glesv2/libGLESv2.la \ + $(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) test_gps_LDFLAGS = -pthread @@ -124,10 +192,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 @@ -139,3 +208,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 + diff --git a/hybris/tests/test_audio.c b/hybris/tests/test_audio.c index c64f7f2d4..a16f469b8 100644 --- a/hybris/tests/test_audio.c +++ b/hybris/tests/test_audio.c @@ -25,11 +25,15 @@ #include #include +/* 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, #if defined(AUDIO_HARDWARE_MODULE_ID_PRIMARY) AUDIO_HARDWARE_MODULE_ID_PRIMARY, @@ -37,17 +41,45 @@ int main(int argc, char **argv) "primary", #endif (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"); #if (ANDROID_VERSION_MAJOR == 4 && ANDROID_VERSION_MINOR >= 1) || (ANDROID_VERSION_MAJOR >= 5) + /* 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); } #endif @@ -55,10 +87,61 @@ int main(int argc, char **argv) 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); } #endif + /* 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; diff --git a/hybris/tests/test_camera.c b/hybris/tests/test_camera.c index 99be5bb59..693a6fb08 100644 --- a/hybris/tests/test_camera.c +++ b/hybris/tests/test_camera.c @@ -15,6 +15,8 @@ * */ +#include "config.h" + #include #include @@ -28,6 +30,7 @@ #include #include +#include #include #include #include @@ -98,8 +101,6 @@ void zoom_msg_cb(void* context, int32_t new_zoom_level) { 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 data_size, void* context) 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++; diff --git a/hybris/tests/test_glesv2.c b/hybris/tests/test_glesv2.c index d58017594..2b6b7f832 100644 --- a/hybris/tests/test_glesv2.c +++ b/hybris/tests/test_glesv2.c @@ -21,6 +21,7 @@ #include #include #include +#include const char vertex_src [] = " \ diff --git a/hybris/tests/test_gps.c b/hybris/tests/test_gps.c index e990db355..4b31625fc 100644 --- a/hybris/tests/test_gps.c +++ b/hybris/tests/test_gps.c @@ -102,17 +102,6 @@ static const GpsNiInterface* get_gps_ni_interface(const GpsInterface *gps) 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; @@ -423,7 +412,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; @@ -460,7 +452,9 @@ int main(int argc, char *argv[]) agps_server = optarg; break; case 'u': +#ifdef HAVE_ULP ulp = 1; +#endif break; case 'x': extra = 1; diff --git a/hybris/tests/test_input.c b/hybris/tests/test_input.c index 785774a9f..3e21ebfb4 100644 --- a/hybris/tests/test_input.c +++ b/hybris/tests/test_input.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -45,7 +46,7 @@ void on_new_event(struct Event* event, void* context) 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); diff --git a/hybris/tests/test_lights.c b/hybris/tests/test_lights.c index 8baf257a5..4dc903618 100644 --- a/hybris/tests/test_lights.c +++ b/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, ¬ifications) == 0); - assert(notifications != 0); + hwmod->methods->open(hwmod, LIGHT_ID_NOTIFICATIONS, (hw_device_t **) ¬ifications); + assert(notifications != NULL); memset(¬ification_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, ¬ification_state) == 0); - light_device_close(notifications); - return 0; } diff --git a/hybris/tests/test_media.c b/hybris/tests/test_media.c new file mode 100644 index 000000000..0ba9f9d9b --- /dev/null +++ b/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 + * Ricardo Salveti de Araujo + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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, ¶ms); + + 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 \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; +} diff --git a/hybris/tests/test_recorder.c b/hybris/tests/test_recorder.c new file mode 100644 index 000000000..bc5aa59a9 --- /dev/null +++ b/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 + * Guenter Schwann + * Ricardo Salveti de Araujo + */ + +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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, ¶ms); + + 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); + } +} diff --git a/hybris/tests/test_ui.c b/hybris/tests/test_ui.c index 184798019..d41dd1a9b 100644 --- a/hybris/tests/test_ui.c +++ b/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); diff --git a/hybris/tests/test_wifi.c b/hybris/tests/test_wifi.c new file mode 100644 index 000000000..478c6373b --- /dev/null +++ b/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 +#include + +#include +#include + +#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 diff --git a/hybris/ui/Makefile.am b/hybris/ui/Makefile.am new file mode 100644 index 000000000..38fdc868e --- /dev/null +++ b/hybris/ui/Makefile.am @@ -0,0 +1,14 @@ +lib_LTLIBRARIES = \ + libui.la + +libui_la_SOURCES = ui.c +libui_la_CFLAGS = -I$(top_srcdir)/include $(ANDROID_HEADERS_CFLAGS) +if WANT_TRACE +libui_la_CFLAGS += -DDEBUG +endif +if WANT_DEBUG +libui_la_CFLAGS += -ggdb -O0 +endif +libui_la_LDFLAGS = \ + $(top_builddir)/common/libhybris-common.la \ + -version-info "1":"0":"0" diff --git a/hybris/ui/ui.c b/hybris/ui/ui.c new file mode 100644 index 000000000..6a56f1d54 --- /dev/null +++ b/hybris/ui/ui.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 Simon Busch + * + * 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 +#include + +#include +#include + +#define COMPAT_LIBRARY_PATH "libui_compat_layer.so" + +HYBRIS_LIBRARY_INITIALIZE(ui, COMPAT_LIBRARY_PATH); + +HYBRIS_IMPLEMENT_FUNCTION0(ui, struct graphic_buffer*, graphic_buffer_new); +HYBRIS_IMPLEMENT_FUNCTION4(ui, struct graphic_buffer*, + graphic_buffer_new_sized, uint32_t, uint32_t, int32_t, uint32_t); +HYBRIS_IMPLEMENT_FUNCTION7(ui, struct graphic_buffer*, graphic_buffer_new_existing, + uint32_t, uint32_t, int32_t, uint32_t, uint32_t, void*, bool); +HYBRIS_IMPLEMENT_VOID_FUNCTION1(ui, graphic_buffer_free, struct graphic_buffer*); +HYBRIS_IMPLEMENT_FUNCTION1(ui, uint32_t, graphic_buffer_get_width, + struct graphic_buffer*); +HYBRIS_IMPLEMENT_FUNCTION1(ui, uint32_t, graphic_buffer_get_height, + struct graphic_buffer*); +HYBRIS_IMPLEMENT_FUNCTION1(ui, uint32_t, graphic_buffer_get_stride, + struct graphic_buffer*); +HYBRIS_IMPLEMENT_FUNCTION1(ui, uint32_t, graphic_buffer_get_usage, + struct graphic_buffer*); +HYBRIS_IMPLEMENT_FUNCTION1(ui, int32_t, graphic_buffer_get_pixel_format, + struct graphic_buffer*); +HYBRIS_IMPLEMENT_FUNCTION5(ui, uint32_t, graphic_buffer_reallocate, + struct graphic_buffer*, uint32_t, uint32_t, int32_t, uint32_t); +HYBRIS_IMPLEMENT_FUNCTION3(ui, uint32_t, graphic_buffer_lock, + struct graphic_buffer*, uint32_t, void**); +HYBRIS_IMPLEMENT_FUNCTION1(ui, uint32_t, graphic_buffer_unlock, + 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*); diff --git a/hybris/utils/getprop.c b/hybris/utils/getprop.c index 7244bd614..945c578d3 100644 --- a/hybris/utils/getprop.c +++ b/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 { diff --git a/hybris/vibrator/vibrator.c b/hybris/vibrator/vibrator.c index c1362035d..aa9d42917 100644 --- a/hybris/vibrator/vibrator.c +++ b/hybris/vibrator/vibrator.c @@ -21,7 +21,7 @@ #include -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); diff --git a/hybris/wifi/Makefile.am b/hybris/wifi/Makefile.am new file mode 100644 index 000000000..ec72e7274 --- /dev/null +++ b/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 diff --git a/hybris/wifi/libwifi.pc.in b/hybris/wifi/libwifi.pc.in new file mode 100644 index 000000000..5abc4228d --- /dev/null +++ b/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} diff --git a/hybris/wifi/wifi.c b/hybris/wifi/wifi.c new file mode 100644 index 000000000..5ce9a94e2 --- /dev/null +++ b/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 + */ + +#include +#include + +#include +#include + +#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); diff --git a/utils/generate_wrapper_macros.py b/utils/generate_wrapper_macros.py index d8b0d8748..6b537ac7d 100644 --- a/utils/generate_wrapper_macros.py +++ b/utils/generate_wrapper_macros.py @@ -104,6 +104,12 @@ 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): diff --git a/utils/load_sym_files.py b/utils/load_sym_files.py index e64729584..4e2759ed1 100644 --- a/utils/load_sym_files.py +++ b/utils/load_sym_files.py @@ -37,19 +37,22 @@ def invoke(self, arg, from_tty): 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 @@ def invoke(self, arg, from_tty): 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()