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;
+            }
         }
     }