Merge "Camera: Hotplug - conditionally transition to PRESENT when clients disconnect" into jb-mr2-dev
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index 6c3e233..a8f9eff 100644
--- a/camera/CameraMetadata.cpp
+++ b/camera/CameraMetadata.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
+
#define LOG_TAG "Camera2-Metadata"
#include <utils/Log.h>
#include <utils/Errors.h>
@@ -112,6 +114,10 @@
}
clear();
mBuffer = buffer;
+
+ ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) != OK,
+ "%s: Failed to validate metadata structure %p",
+ __FUNCTION__, buffer);
}
void CameraMetadata::acquire(CameraMetadata &other) {
@@ -289,6 +295,15 @@
__FUNCTION__, get_camera_metadata_section_name(tag),
get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
}
+
+ IF_ALOGV() {
+ ALOGE_IF(validate_camera_metadata_structure(mBuffer, /*size*/NULL) !=
+ OK,
+
+ "%s: Failed to validate metadata structure after update %p",
+ __FUNCTION__, mBuffer);
+ }
+
return res;
}
diff --git a/camera/IProCameraUser.cpp b/camera/IProCameraUser.cpp
index 0c94bd4..4c4dec3 100644
--- a/camera/IProCameraUser.cpp
+++ b/camera/IProCameraUser.cpp
@@ -50,17 +50,30 @@
* Caller becomes the owner of the new metadata
* 'const Parcel' doesnt prevent us from calling the read functions.
* which is interesting since it changes the internal state
+ *
+ * NULL can be returned when no metadata was sent, OR if there was an issue
+ * unpacking the serialized data (i.e. bad parcel or invalid structure).
*/
void readMetadata(const Parcel& data, camera_metadata_t** out) {
- camera_metadata_t* metadata;
+
+ status_t err = OK;
+
+ camera_metadata_t* metadata = NULL;
+
+ if (out) {
+ *out = NULL;
+ }
// arg0 = metadataSize (int32)
- size_t metadataSize = static_cast<size_t>(data.readInt32());
+ int32_t metadataSizeTmp = -1;
+ if ((err = data.readInt32(&metadataSizeTmp)) != OK) {
+ ALOGE("%s: Failed to read metadata size (error %d %s)",
+ __FUNCTION__, err, strerror(-err));
+ return;
+ }
+ const size_t metadataSize = static_cast<size_t>(metadataSizeTmp);
if (metadataSize == 0) {
- if (out) {
- *out = NULL;
- }
return;
}
@@ -70,21 +83,23 @@
ReadableBlob blob;
// arg1 = metadata (blob)
- {
- data.readBlob(metadataSize, &blob);
+ do {
+ if ((err = data.readBlob(metadataSize, &blob)) != OK) {
+ ALOGE("%s: Failed to read metadata blob (sized %d). Possible "
+ " serialization bug. Error %d %s",
+ __FUNCTION__, metadataSize, err, strerror(-err));
+ break;
+ }
const camera_metadata_t* tmp =
reinterpret_cast<const camera_metadata_t*>(blob.data());
- size_t entry_capacity = get_camera_metadata_entry_capacity(tmp);
- size_t data_capacity = get_camera_metadata_data_capacity(tmp);
- metadata = allocate_camera_metadata(entry_capacity, data_capacity);
- copy_camera_metadata(metadata, metadataSize, tmp);
- }
+ metadata = allocate_copy_camera_metadata_checked(tmp, metadataSize);
+ } while(0);
blob.release();
if (out) {
*out = metadata;
- } else {
+ } else if (metadata != NULL) {
free_camera_metadata(metadata);
}
}
@@ -95,14 +110,13 @@
*/
void writeMetadata(Parcel& data, camera_metadata_t* metadata) {
// arg0 = metadataSize (int32)
- size_t metadataSize;
if (metadata == NULL) {
data.writeInt32(0);
return;
}
- metadataSize = get_camera_metadata_compact_size(metadata);
+ const size_t metadataSize = get_camera_metadata_compact_size(metadata);
data.writeInt32(static_cast<int32_t>(metadataSize));
// arg1 = metadata (blob)
@@ -110,6 +124,25 @@
{
data.writeBlob(metadataSize, &blob);
copy_camera_metadata(blob.data(), metadataSize, metadata);
+
+ IF_ALOGV() {
+ if (validate_camera_metadata_structure(
+ (const camera_metadata_t*)blob.data(),
+ &metadataSize) != OK) {
+ ALOGV("%s: Failed to validate metadata %p after writing blob",
+ __FUNCTION__, blob.data());
+ } else {
+ ALOGV("%s: Metadata written to blob. Validation success",
+ __FUNCTION__);
+ }
+ }
+
+ // Not too big of a problem since receiving side does hard validation
+ if (validate_camera_metadata_structure(metadata, &metadataSize) != OK) {
+ ALOGW("%s: Failed to validate metadata %p before writing blob",
+ __FUNCTION__, metadata);
+ }
+
}
blob.release();
}
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index db5a7ab..64f82bb 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -599,6 +599,7 @@
int mPreviousPriority; // before start()
SchedPolicy mPreviousSchedulingGroup;
AudioTrackClientProxy* mProxy;
+ bool mAwaitBoost; // thread should wait for priority boost before running
};
class TimedAudioTrack : public AudioTrack
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 1bd839f..7eeb4f8 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -893,9 +893,11 @@
ALOGW("Requested frameCount %u but received frameCount %u", frameCount, temp);
}
frameCount = temp;
+ mAwaitBoost = false;
if (flags & AUDIO_OUTPUT_FLAG_FAST) {
if (trackFlags & IAudioFlinger::TRACK_FAST) {
ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %u", frameCount);
+ mAwaitBoost = true;
} else {
ALOGV("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", frameCount);
// once denied, do not request again if IAudioTrack is re-created
@@ -1219,6 +1221,25 @@
size_t writtenSize;
mLock.lock();
+ if (mAwaitBoost) {
+ mAwaitBoost = false;
+ mLock.unlock();
+ static const int32_t kMaxTries = 5;
+ int32_t tryCounter = kMaxTries;
+ uint32_t pollUs = 10000;
+ do {
+ int policy = sched_getscheduler(0);
+ if (policy == SCHED_FIFO || policy == SCHED_RR) {
+ break;
+ }
+ usleep(pollUs);
+ pollUs <<= 1;
+ } while (tryCounter-- > 0);
+ if (tryCounter < 0) {
+ ALOGE("did not receive expected priority boost on time");
+ }
+ return true;
+ }
// acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
// while we are accessing the cblk
sp<IAudioTrack> audioTrack = mAudioTrack;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d0ef922..b0efef6 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -588,11 +588,12 @@
status_t closeOutput_nonvirtual(audio_io_handle_t output);
status_t closeInput_nonvirtual(audio_io_handle_t input);
-#ifdef TEE_SINK
+// do not use #ifdef here, since AudioFlinger.h is included by more than one module
+//#ifdef TEE_SINK
// all record threads serially share a common tee sink, which is re-created on format change
sp<NBAIO_Sink> mRecordTeeSink;
sp<NBAIO_Source> mRecordTeeSource;
-#endif
+//#endif
public:
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 24a6dfe..21df1d7 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -170,6 +170,10 @@
if (old <= 0) {
__futex_syscall4(coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, NULL);
}
+ int policy = sched_getscheduler(0);
+ if (!(policy == SCHED_FIFO || policy == SCHED_RR)) {
+ ALOGE("did not receive expected priority boost");
+ }
// This may be overly conservative; there could be times that the normal mixer
// requests such a brief cold idle that it doesn't require resetting this flag.
isWarm = false;
diff --git a/services/audioflinger/ISchedulingPolicyService.cpp b/services/audioflinger/ISchedulingPolicyService.cpp
index 218aa6b..0079968 100644
--- a/services/audioflinger/ISchedulingPolicyService.cpp
+++ b/services/audioflinger/ISchedulingPolicyService.cpp
@@ -37,14 +37,15 @@
{
}
- virtual int requestPriority(int32_t pid, int32_t tid, int32_t prio)
+ virtual int requestPriority(int32_t pid, int32_t tid, int32_t prio, bool asynchronous)
{
Parcel data, reply;
data.writeInterfaceToken(ISchedulingPolicyService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeInt32(tid);
data.writeInt32(prio);
- remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+ uint32_t flags = asynchronous ? IBinder::FLAG_ONEWAY : 0;
+ remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply, flags);
// fail on exception
if (reply.readExceptionCode() != 0) return -1;
return reply.readInt32();
diff --git a/services/audioflinger/ISchedulingPolicyService.h b/services/audioflinger/ISchedulingPolicyService.h
index a38e67e..b94b191 100644
--- a/services/audioflinger/ISchedulingPolicyService.h
+++ b/services/audioflinger/ISchedulingPolicyService.h
@@ -27,7 +27,7 @@
DECLARE_META_INTERFACE(SchedulingPolicyService);
virtual int requestPriority(/*pid_t*/int32_t pid, /*pid_t*/int32_t tid,
- int32_t prio) = 0;
+ int32_t prio, bool asynchronous) = 0;
};
diff --git a/services/audioflinger/SchedulingPolicyService.cpp b/services/audioflinger/SchedulingPolicyService.cpp
index 59cc99a..36e62e9 100644
--- a/services/audioflinger/SchedulingPolicyService.cpp
+++ b/services/audioflinger/SchedulingPolicyService.cpp
@@ -25,7 +25,7 @@
static const String16 _scheduling_policy("scheduling_policy");
static Mutex sMutex;
-int requestPriority(pid_t pid, pid_t tid, int32_t prio)
+int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous)
{
// FIXME merge duplicated code related to service lookup, caching, and error recovery
sp<ISchedulingPolicyService> sps;
@@ -46,7 +46,7 @@
}
sleep(1);
}
- return sps->requestPriority(pid, tid, prio);
+ return sps->requestPriority(pid, tid, prio, asynchronous);
}
} // namespace android
diff --git a/services/audioflinger/SchedulingPolicyService.h b/services/audioflinger/SchedulingPolicyService.h
index 7ac8454..a9870d4 100644
--- a/services/audioflinger/SchedulingPolicyService.h
+++ b/services/audioflinger/SchedulingPolicyService.h
@@ -21,7 +21,10 @@
// Request elevated priority for thread tid, whose thread group leader must be pid.
// The priority parameter is currently restricted to either 1 or 2.
-int requestPriority(pid_t pid, pid_t tid, int32_t prio);
+// The asynchronous parameter should be 'true' to return immediately,
+// after the request is enqueued but not necessarily executed.
+// The default value 'false' means to return after request has been enqueued and executed.
+int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous = false);
} // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 47ca100..539bb4f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -373,7 +373,9 @@
switch(event->type()) {
case CFG_EVENT_PRIO: {
PrioConfigEvent *prioEvent = static_cast<PrioConfigEvent *>(event);
- int err = requestPriority(prioEvent->pid(), prioEvent->tid(), prioEvent->prio());
+ // FIXME Need to understand why this has be done asynchronously
+ int err = requestPriority(prioEvent->pid(), prioEvent->tid(), prioEvent->prio(),
+ true /*asynchronous*/);
if (err != 0) {
ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; "
"error %d",
diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp
index 5f87e8b..5e5bfc2 100644
--- a/services/camera/libcameraservice/Camera3Device.cpp
+++ b/services/camera/libcameraservice/Camera3Device.cpp
@@ -1060,7 +1060,7 @@
// TODO: Try to relax this later back to lazy completion, which should be
// faster
- if (mInputStream != NULL) {
+ if (mInputStream != NULL && mInputStream->isConfiguring()) {
res = mInputStream->finishConfiguration(mHal3Device);
if (res != OK) {
SET_ERR_L("Can't finish configuring input stream %d: %s (%d)",
@@ -1070,11 +1070,15 @@
}
for (size_t i = 0; i < mOutputStreams.size(); i++) {
- res = mOutputStreams.editValueAt(i)->finishConfiguration(mHal3Device);
- if (res != OK) {
- SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
- mOutputStreams[i]->getId(), strerror(-res), res);
- return res;
+ sp<Camera3OutputStreamInterface> outputStream =
+ mOutputStreams.editValueAt(i);
+ if (outputStream->isConfiguring()) {
+ res = outputStream->finishConfiguration(mHal3Device);
+ if (res != OK) {
+ SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
+ outputStream->getId(), strerror(-res), res);
+ return res;
+ }
}
}