Merge changes Ib7227f18,I96926932,I46476112,I2c17b1e4,I47ee9e39, ... am: c809601217 am: 534edb5808
am: cf5c9d616c
Change-Id: I7adf6faf859354ddd1cb93b143514c2ae16152ea
diff --git a/hardware.c b/hardware.c
index 40ae1d1..6e72ce9 100644
--- a/hardware.c
+++ b/hardware.c
@@ -24,6 +24,7 @@
#include <errno.h>
#include <limits.h>
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
#define LOG_TAG "HAL"
@@ -148,6 +149,25 @@
}
/*
+ * If path is in in_path.
+ */
+static bool path_in_path(const char *path, const char *in_path) {
+ char real_path[PATH_MAX];
+ if (realpath(path, real_path) == NULL) return false;
+
+ char real_in_path[PATH_MAX];
+ if (realpath(in_path, real_in_path) == NULL) return false;
+
+ const size_t real_in_path_len = strlen(real_in_path);
+ if (strncmp(real_path, real_in_path, real_in_path_len) != 0) {
+ return false;
+ }
+
+ return strlen(real_path) > real_in_path_len &&
+ real_path[real_in_path_len] == '/';
+}
+
+/*
* Check if a HAL with given name and subname exists, if so return 0, otherwise
* otherwise return negative. On success path will contain the path to the HAL.
*/
@@ -156,18 +176,18 @@
{
snprintf(path, path_len, "%s/%s.%s.so",
HAL_LIBRARY_PATH3, name, subname);
- if (access(path, R_OK) == 0)
+ if (path_in_path(path, HAL_LIBRARY_PATH3) && access(path, R_OK) == 0)
return 0;
snprintf(path, path_len, "%s/%s.%s.so",
HAL_LIBRARY_PATH2, name, subname);
- if (access(path, R_OK) == 0)
+ if (path_in_path(path, HAL_LIBRARY_PATH2) && access(path, R_OK) == 0)
return 0;
#ifndef __ANDROID_VNDK__
snprintf(path, path_len, "%s/%s.%s.so",
HAL_LIBRARY_PATH1, name, subname);
- if (access(path, R_OK) == 0)
+ if (path_in_path(path, HAL_LIBRARY_PATH1) && access(path, R_OK) == 0)
return 0;
#endif
diff --git a/include/hardware/hwcomposer2.h b/include/hardware/hwcomposer2.h
index c9809ce..71831a0 100644
--- a/include/hardware/hwcomposer2.h
+++ b/include/hardware/hwcomposer2.h
@@ -270,7 +270,8 @@
HWC2_FUNCTION_GET_READBACK_BUFFER_FENCE,
HWC2_FUNCTION_GET_RENDER_INTENTS,
HWC2_FUNCTION_SET_COLOR_MODE_WITH_RENDER_INTENT,
- HWC2_FUNCTION_GET_DATASPACE_SATURATION_MATRIX
+ HWC2_FUNCTION_GET_DATASPACE_SATURATION_MATRIX,
+ HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA
} hwc2_function_descriptor_t;
/* Layer requests returned from getDisplayRequests */
@@ -524,6 +525,7 @@
case HWC2_FUNCTION_GET_RENDER_INTENTS: return "GetRenderIntents";
case HWC2_FUNCTION_SET_COLOR_MODE_WITH_RENDER_INTENT: return "SetColorModeWithRenderIntent";
case HWC2_FUNCTION_GET_DATASPACE_SATURATION_MATRIX: return "GetDataspaceSaturationMatrix";
+ case HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA: return "GetDisplayIdentificationData";
default: return "Unknown";
}
}
@@ -722,6 +724,7 @@
GetRenderIntents = HWC2_FUNCTION_GET_RENDER_INTENTS,
SetColorModeWithRenderIntent = HWC2_FUNCTION_SET_COLOR_MODE_WITH_RENDER_INTENT,
GetDataspaceSaturationMatrix = HWC2_FUNCTION_GET_DATASPACE_SATURATION_MATRIX,
+ GetDisplayIdentificationData = HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA,
};
TO_STRING(hwc2_function_descriptor_t, FunctionDescriptor,
getFunctionDescriptorName)
@@ -1374,6 +1377,35 @@
hwc2_device_t* device, hwc2_display_t display,
int32_t* /*hwc2_display_type_t*/ outType);
+/* getDisplayIdentificationData(..., outPort, outDataSize, outData)
+ * Descriptor: HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA
+ * Optional for HWC2 devices
+ *
+ * If supported, getDisplayIdentificationData returns the port and data that
+ * describe a physical display. The port is a unique number that identifies a
+ * physical connector (e.g. eDP, HDMI) for display output. The data blob is
+ * parsed to determine its format, typically EDID 1.3 as specified in VESA
+ * E-EDID Standard Release A Revision 1.
+ *
+ * Devices for which display identification is unsupported must return null when
+ * getFunction is called with HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA.
+ *
+ * Parameters:
+ * outPort - the connector to which the display is connected;
+ * pointer will be non-NULL
+ * outDataSize - if outData is NULL, the size in bytes of the data which would
+ * have been returned; if outData is not NULL, the size of outData, which
+ * must not exceed the value stored in outDataSize prior to the call;
+ * pointer will be non-NULL
+ * outData - the EDID 1.3 blob identifying the display
+ *
+ * Returns HWC2_ERROR_NONE or one of the following errors:
+ * HWC2_ERROR_BAD_DISPLAY - an invalid display handle was passed in
+ */
+typedef int32_t /*hwc2_error_t*/ (*HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA)(
+ hwc2_device_t* device, hwc2_display_t display, uint8_t* outPort,
+ uint32_t* outDataSize, uint8_t* outData);
+
/* getDozeSupport(..., outSupport)
* Descriptor: HWC2_FUNCTION_GET_DOZE_SUPPORT
* Must be provided by all HWC2 devices
diff --git a/modules/usbaudio/audio_hal.c b/modules/usbaudio/audio_hal.c
index 81c9fd6..d797a21 100644
--- a/modules/usbaudio/audio_hal.c
+++ b/modules/usbaudio/audio_hal.c
@@ -47,6 +47,9 @@
/* Lock play & record samples rates at or above this threshold */
#define RATELOCK_THRESHOLD 96000
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
struct audio_device {
struct audio_hw_device hw_device;
@@ -62,7 +65,7 @@
/* lock input & output sample rates */
/*FIXME - How do we address multiple output streams? */
- uint32_t device_sample_rate;
+ uint32_t device_sample_rate; // this should be a rate that is common to both input & output
bool mic_muted;
@@ -597,6 +600,7 @@
ret = -EINVAL;
}
+ /* TODO: This is a problem if the input does not support this rate */
out->adev->device_sample_rate = config->sample_rate;
device_unlock(out->adev);
@@ -929,6 +933,19 @@
return 0;
}
+static int in_get_capture_position(const struct audio_stream_in *stream,
+ int64_t *frames, int64_t *time)
+{
+ struct stream_in *in = (struct stream_in *)stream; // discard const qualifier
+ stream_lock(&in->lock);
+
+ const alsa_device_proxy *proxy = &in->proxy;
+ const int ret = proxy_get_capture_position(proxy, frames, time);
+
+ stream_unlock(&in->lock);
+ return ret;
+}
+
static int adev_open_input_stream(struct audio_hw_device *hw_dev,
audio_io_handle_t handle,
audio_devices_t devicesSpec __unused,
@@ -972,6 +989,7 @@
in->stream.set_gain = in_set_gain;
in->stream.read = in_read;
in->stream.get_input_frames_lost = in_get_input_frames_lost;
+ in->stream.get_capture_position = in_get_capture_position;
stream_lock_init(&in->lock);
@@ -1008,20 +1026,36 @@
}
/* Rate */
+ int request_config_rate = config->sample_rate;
if (config->sample_rate == 0) {
config->sample_rate = profile_get_default_sample_rate(in->profile);
}
- if (in->adev->device_sample_rate != 0 && /* we are playing, so lock the rate */
+ if (in->adev->device_sample_rate != 0 && /* we are playing, so lock the rate if possible */
in->adev->device_sample_rate >= RATELOCK_THRESHOLD) {/* but only for high sample rates */
- ret = config->sample_rate != in->adev->device_sample_rate ? -EINVAL : 0;
- proxy_config.rate = config->sample_rate = in->adev->device_sample_rate;
+ if (config->sample_rate != in->adev->device_sample_rate) {
+ unsigned highest_rate = profile_get_highest_sample_rate(in->profile);
+ if (highest_rate == 0) {
+ ret = -EINVAL; /* error with device */
+ } else {
+ proxy_config.rate = config->sample_rate =
+ min(highest_rate, in->adev->device_sample_rate);
+ if (request_config_rate != 0 && proxy_config.rate != config->sample_rate) {
+ /* Changing the requested rate */
+ ret = -EINVAL;
+ } else {
+ /* Everything AOK! */
+ ret = 0;
+ }
+ }
+ }
} else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) {
proxy_config.rate = config->sample_rate;
} else {
proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
ret = -EINVAL;
}
+
device_unlock(in->adev);
/* Format */