Merge "libstagefright: fix possible overflow in SampleTable.cpp" into mnc-dev
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 7c9720f..b359f57 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -94,11 +94,18 @@
     {
     }
 
-    // get number of cameras available
+    // get number of cameras available that support standard camera operations
     virtual int32_t getNumberOfCameras()
     {
+        return getNumberOfCameras(CAMERA_TYPE_BACKWARD_COMPATIBLE);
+    }
+
+    // get number of cameras available of a given type
+    virtual int32_t getNumberOfCameras(int type)
+    {
         Parcel data, reply;
         data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+        data.writeInt32(type);
         remote()->transact(BnCameraService::GET_NUMBER_OF_CAMERAS, data, &reply);
 
         if (readExceptionCode(reply)) return 0;
@@ -337,7 +344,7 @@
         case GET_NUMBER_OF_CAMERAS: {
             CHECK_INTERFACE(ICameraService, data, reply);
             reply->writeNoException();
-            reply->writeInt32(getNumberOfCameras());
+            reply->writeInt32(getNumberOfCameras(data.readInt32()));
             return NO_ERROR;
         } break;
         case GET_CAMERA_INFO: {
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index 5f85635..1b68b5f 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -64,6 +64,11 @@
     };
 
     enum {
+        CAMERA_TYPE_BACKWARD_COMPATIBLE = 0,
+        CAMERA_TYPE_ALL = 1,
+    };
+
+    enum {
         CAMERA_HAL_API_VERSION_UNSPECIFIED = -1
     };
 
@@ -81,7 +86,12 @@
 public:
     DECLARE_META_INTERFACE(CameraService);
 
+    // Get the number of cameras that support basic color camera operation
+    // (type CAMERA_TYPE_BACKWARD_COMPATIBLE)
     virtual int32_t  getNumberOfCameras() = 0;
+    // Get the number of cameras of the specified type, one of CAMERA_TYPE_*
+    // enums
+    virtual int32_t  getNumberOfCameras(int cameraType) = 0;
     virtual status_t getCameraInfo(int cameraId,
             /*out*/
             struct CameraInfo* cameraInfo) = 0;
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 05f6786..8b5b862 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -236,6 +236,7 @@
     bool mSentFormat;
     bool mIsVideo;
     bool mIsEncoder;
+    bool mFatalError;
     bool mShutdownInProgress;
     bool mExplicitShutdown;
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index fb654b8..8d9bd21 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -497,6 +497,7 @@
       mSentFormat(false),
       mIsVideo(false),
       mIsEncoder(false),
+      mFatalError(false),
       mShutdownInProgress(false),
       mExplicitShutdown(false),
       mEncoderDelay(0),
@@ -1312,6 +1313,11 @@
         return NULL;
     }
 
+    if (mFatalError) {
+        ALOGW("not dequeuing from native window due to fatal error");
+        return NULL;
+    }
+
     int fenceFd = -1;
     do {
         status_t err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd);
@@ -4460,6 +4466,9 @@
             ALOGW("Invalid OMX error %#x", error);
         }
     }
+
+    mFatalError = true;
+
     notify->setInt32("err", internalError);
     notify->setInt32("actionCode", ACTION_CODE_FATAL); // could translate from OMX error.
     notify->post();
diff --git a/media/libstagefright/codecs/amrwbenc/src/util.c b/media/libstagefright/codecs/amrwbenc/src/util.c
index 76ab1b1..333140d 100644
--- a/media/libstagefright/codecs/amrwbenc/src/util.c
+++ b/media/libstagefright/codecs/amrwbenc/src/util.c
@@ -35,9 +35,10 @@
 	     )
 {
 	Word32 num = (Word32)L;
-	do{
+	while (num > 0) {
 		*x++ = 0;
-	}while(--num !=0);
+                --num;
+	}
 }
 
 
@@ -54,20 +55,22 @@
 	 )
 {
 	Word32	temp1,temp2,num;
+        if (L <= 0) {
+                return;
+        }
 	if(L&1)
 	{
 		temp1 = *x++;
 		*y++ = temp1;
 	}
 	num = (Word32)(L>>1);
-	temp1 = *x++;
-	temp2 = *x++;
-	do{
-		*y++ = temp1;
-		*y++ = temp2;
+	while (num > 0) {
 		temp1 = *x++;
 		temp2 = *x++;
-	}while(--num!=0);
+		*y++ = temp1;
+		*y++ = temp2;
+                --num;
+	}
 }
 
 
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 38ba844..29bc9e0 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -327,7 +327,7 @@
     size_t oldSize = mSize;
 
     size_t offset = 0;
-    while (offset + 10 <= mSize) {
+    while (mSize >= 10 && offset <= mSize - 10) {
         if (!memcmp(&mData[offset], "\0\0\0\0", 4)) {
             break;
         }
@@ -339,7 +339,7 @@
             return false;
         }
 
-        if (offset + dataSize + 10 > mSize) {
+        if (dataSize > mSize - 10 - offset) {
             return false;
         }
 
@@ -349,6 +349,9 @@
         if (flags & 1) {
             // Strip data length indicator
 
+            if (mSize < 14 || mSize - 14 < offset) {
+                return false;
+            }
             memmove(&mData[offset + 10], &mData[offset + 14], mSize - offset - 14);
             mSize -= 4;
             dataSize -= 4;
@@ -506,6 +509,9 @@
         return;
     }
 
+    if (mFrameSize < getHeaderLength() + 1) {
+        return;
+    }
     size_t n = mFrameSize - getHeaderLength() - 1;
     if (otherdata) {
         // skip past the encoding, language, and the 0 separator
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 92df4e3..43a8ec4 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -171,6 +171,7 @@
     }
 
     mNumberOfCameras = mModule->getNumberOfCameras();
+    mNumberOfNormalCameras = mNumberOfCameras;
 
     mFlashlight = new CameraFlashlight(*mModule, *this);
     status_t res = mFlashlight->findFlashUnits();
@@ -179,27 +180,41 @@
         ALOGE("Failed to find flash units.");
     }
 
+    int latestStrangeCameraId = INT_MAX;
     for (int i = 0; i < mNumberOfCameras; i++) {
         String8 cameraId = String8::format("%d", i);
 
+        // Get camera info
+
+        struct camera_info info;
+        bool haveInfo = true;
+        status_t rc = mModule->getCameraInfo(i, &info);
+        if (rc != NO_ERROR) {
+            ALOGE("%s: Received error loading camera info for device %d, cost and"
+                    " conflicting devices fields set to defaults for this device.",
+                    __FUNCTION__, i);
+            haveInfo = false;
+        }
+
+        // Check for backwards-compatibility support
+        if (haveInfo) {
+            if (checkCameraCapabilities(i, info, &latestStrangeCameraId) != OK) {
+                delete mModule;
+                mModule = nullptr;
+                return;
+            }
+        }
+
         // Defaults to use for cost and conflicting devices
         int cost = 100;
         char** conflicting_devices = nullptr;
         size_t conflicting_devices_length = 0;
 
         // If using post-2.4 module version, query the cost + conflicting devices from the HAL
-        if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
-            struct camera_info info;
-            status_t rc = mModule->getCameraInfo(i, &info);
-            if (rc == NO_ERROR) {
-                cost = info.resource_cost;
-                conflicting_devices = info.conflicting_devices;
-                conflicting_devices_length = info.conflicting_devices_length;
-            } else {
-                ALOGE("%s: Received error loading camera info for device %d, cost and"
-                        " conflicting devices fields set to defaults for this device.",
-                        __FUNCTION__, i);
-            }
+        if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 && haveInfo) {
+            cost = info.resource_cost;
+            conflicting_devices = info.conflicting_devices;
+            conflicting_devices_length = info.conflicting_devices_length;
         }
 
         std::set<String8> conflicting;
@@ -382,9 +397,21 @@
     }
 }
 
-
 int32_t CameraService::getNumberOfCameras() {
-    return mNumberOfCameras;
+    return getNumberOfCameras(CAMERA_TYPE_BACKWARD_COMPATIBLE);
+}
+
+int32_t CameraService::getNumberOfCameras(int type) {
+    switch (type) {
+        case CAMERA_TYPE_BACKWARD_COMPATIBLE:
+            return mNumberOfNormalCameras;
+        case CAMERA_TYPE_ALL:
+            return mNumberOfCameras;
+        default:
+            ALOGW("%s: Unknown camera type %d, returning 0",
+                    __FUNCTION__, type);
+            return 0;
+    }
 }
 
 status_t CameraService::getCameraInfo(int cameraId,
@@ -1494,6 +1521,53 @@
 }
 
 
+/**
+ * Check camera capabilities, such as support for basic color operation
+ */
+int CameraService::checkCameraCapabilities(int id, camera_info info, int *latestStrangeCameraId) {
+
+    // Assume all devices pre-v3.3 are backward-compatible
+    bool isBackwardCompatible = true;
+    if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0
+            && info.device_version >= CAMERA_DEVICE_API_VERSION_3_3) {
+        isBackwardCompatible = false;
+        status_t res;
+        camera_metadata_ro_entry_t caps;
+        res = find_camera_metadata_ro_entry(
+            info.static_camera_characteristics,
+            ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
+            &caps);
+        if (res != 0) {
+            ALOGW("%s: Unable to find camera capabilities for camera device %d",
+                    __FUNCTION__, id);
+            caps.count = 0;
+        }
+        for (size_t i = 0; i < caps.count; i++) {
+            if (caps.data.u8[i] ==
+                    ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) {
+                isBackwardCompatible = true;
+                break;
+            }
+        }
+    }
+
+    if (!isBackwardCompatible) {
+        mNumberOfNormalCameras--;
+        *latestStrangeCameraId = id;
+    } else {
+        if (id > *latestStrangeCameraId) {
+            ALOGE("%s: Normal camera ID %d higher than strange camera ID %d. "
+                    "This is not allowed due backward-compatibility requirements",
+                    __FUNCTION__, id, *latestStrangeCameraId);
+            logServiceError("Invalid order of camera devices", ENODEV);
+            mNumberOfCameras = 0;
+            mNumberOfNormalCameras = 0;
+            return INVALID_OPERATION;
+        }
+    }
+    return OK;
+}
+
 std::shared_ptr<CameraService::CameraState> CameraService::getCameraState(
         const String8& cameraId) const {
     std::shared_ptr<CameraState> state;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 3298772..7f4d43f 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -100,7 +100,9 @@
 
     /////////////////////////////////////////////////////////////////////
     // ICameraService
+    virtual int32_t     getNumberOfCameras(int type);
     virtual int32_t     getNumberOfCameras();
+
     virtual status_t    getCameraInfo(int cameraId,
                                       struct CameraInfo* cameraInfo);
     virtual status_t    getCameraCharacteristics(int cameraId,
@@ -509,6 +511,11 @@
     std::set<userid_t> mAllowedUsers;
 
     /**
+     * Check camera capabilities, such as support for basic color operation
+     */
+    int checkCameraCapabilities(int id, camera_info info, int *latestStrangeCameraId);
+
+    /**
      * Get the camera state for a given camera id.
      *
      * This acquires mCameraStatesLock.
@@ -610,6 +617,7 @@
     void dumpEventLog(int fd);
 
     int                 mNumberOfCameras;
+    int                 mNumberOfNormalCameras;
 
     // sounds
     MediaPlayer*        newMediaPlayer(const char *file);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 3afbd89..0c941fb 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -60,6 +60,7 @@
         mIsConstrainedHighSpeedConfiguration(false),
         mHal3Device(NULL),
         mStatus(STATUS_UNINITIALIZED),
+        mStatusWaiters(0),
         mUsePartialResult(false),
         mNumPartialResults(1),
         mNextResultFrameNumber(0),
@@ -191,7 +192,8 @@
     mDeviceVersion = device->common.version;
     mDeviceInfo = info.static_camera_characteristics;
     mHal3Device = device;
-    mStatus = STATUS_UNCONFIGURED;
+
+    internalUpdateStatusLocked(STATUS_UNCONFIGURED);
     mNextStreamId = 0;
     mDummyStreamId = NO_STREAM;
     mNeedConfig = true;
@@ -296,7 +298,7 @@
             mHal3Device = NULL;
         }
 
-        mStatus = STATUS_UNINITIALIZED;
+        internalUpdateStatusLocked(STATUS_UNINITIALIZED);
     }
 
     ALOGV("%s: X", __FUNCTION__);
@@ -370,7 +372,7 @@
     // Get max jpeg size (area-wise).
     Size maxJpegResolution = getMaxJpegResolution();
     if (maxJpegResolution.width == 0) {
-        ALOGE("%s: Camera %d: Can't find find valid available jpeg sizes in static metadata!",
+        ALOGE("%s: Camera %d: Can't find valid available jpeg sizes in static metadata!",
                 __FUNCTION__, mId);
         return BAD_VALUE;
     }
@@ -397,6 +399,21 @@
     return jpegBufferSize;
 }
 
+ssize_t Camera3Device::getPointCloudBufferSize() const {
+    const int FLOATS_PER_POINT=4;
+    camera_metadata_ro_entry maxPointCount = mDeviceInfo.find(ANDROID_DEPTH_MAX_DEPTH_SAMPLES);
+    if (maxPointCount.count == 0) {
+        ALOGE("%s: Camera %d: Can't find maximum depth point cloud size in static metadata!",
+                __FUNCTION__, mId);
+        return BAD_VALUE;
+    }
+    ssize_t maxBytesForPointCloud = sizeof(android_depth_points) +
+            maxPointCount.data.i32[0] * sizeof(float) * FLOATS_PER_POINT;
+    return maxBytesForPointCloud;
+}
+
+
+
 status_t Camera3Device::dump(int fd, const Vector<String16> &args) {
     ATRACE_CALL();
     (void)args;
@@ -865,14 +882,22 @@
 
     sp<Camera3OutputStream> newStream;
     if (format == HAL_PIXEL_FORMAT_BLOB) {
-        ssize_t jpegBufferSize = getJpegBufferSize(width, height);
-        if (jpegBufferSize <= 0) {
-            SET_ERR_L("Invalid jpeg buffer size %zd", jpegBufferSize);
-            return BAD_VALUE;
+        ssize_t blobBufferSize;
+        if (dataSpace != HAL_DATASPACE_DEPTH) {
+            blobBufferSize = getJpegBufferSize(width, height);
+            if (blobBufferSize <= 0) {
+                SET_ERR_L("Invalid jpeg buffer size %zd", blobBufferSize);
+                return BAD_VALUE;
+            }
+        } else {
+            blobBufferSize = getPointCloudBufferSize();
+            if (blobBufferSize <= 0) {
+                SET_ERR_L("Invalid point cloud buffer size %zd", blobBufferSize);
+                return BAD_VALUE;
+            }
         }
-
         newStream = new Camera3OutputStream(mNextStreamId, consumer,
-                width, height, jpegBufferSize, format, dataSpace, rotation);
+                width, height, blobBufferSize, format, dataSpace, rotation);
     } else {
         newStream = new Camera3OutputStream(mNextStreamId, consumer,
                 width, height, format, dataSpace, rotation);
@@ -1143,6 +1168,13 @@
     return res;
 }
 
+
+void Camera3Device::internalUpdateStatusLocked(Status status) {
+    mStatus = status;
+    mRecentStatusUpdates.add(mStatus);
+    mStatusChanged.broadcast();
+}
+
 // Pause to reconfigure
 status_t Camera3Device::internalPauseAndWaitLocked() {
     mRequestThread->setPaused(true);
@@ -1173,23 +1205,40 @@
     return OK;
 }
 
-status_t Camera3Device::waitUntilStateThenRelock(bool active,
-        nsecs_t timeout) {
+status_t Camera3Device::waitUntilStateThenRelock(bool active, nsecs_t timeout) {
     status_t res = OK;
-    if (active == (mStatus == STATUS_ACTIVE)) {
-        // Desired state already reached
-        return res;
+
+    size_t startIndex = 0;
+    if (mStatusWaiters == 0) {
+        // Clear the list of recent statuses if there are no existing threads waiting on updates to
+        // this status list
+        mRecentStatusUpdates.clear();
+    } else {
+        // If other threads are waiting on updates to this status list, set the position of the
+        // first element that this list will check rather than clearing the list.
+        startIndex = mRecentStatusUpdates.size();
     }
 
+    mStatusWaiters++;
+
     bool stateSeen = false;
     do {
-        mRecentStatusUpdates.clear();
+        if (active == (mStatus == STATUS_ACTIVE)) {
+            // Desired state is current
+            break;
+        }
 
         res = mStatusChanged.waitRelative(mLock, timeout);
         if (res != OK) break;
 
-        // Check state change history during wait
-        for (size_t i = 0; i < mRecentStatusUpdates.size(); i++) {
+        // This is impossible, but if not, could result in subtle deadlocks and invalid state
+        // transitions.
+        LOG_ALWAYS_FATAL_IF(startIndex > mRecentStatusUpdates.size(),
+                "%s: Skipping status updates in Camera3Device, may result in deadlock.",
+                __FUNCTION__);
+
+        // Encountered desired state since we began waiting
+        for (size_t i = startIndex; i < mRecentStatusUpdates.size(); i++) {
             if (active == (mRecentStatusUpdates[i] == STATUS_ACTIVE) ) {
                 stateSeen = true;
                 break;
@@ -1197,6 +1246,8 @@
         }
     } while (!stateSeen);
 
+    mStatusWaiters--;
+
     return res;
 }
 
@@ -1438,9 +1489,7 @@
         }
         ALOGV("%s: Camera %d: Now %s", __FUNCTION__, mId,
                 idle ? "idle" : "active");
-        mStatus = idle ? STATUS_CONFIGURED : STATUS_ACTIVE;
-        mRecentStatusUpdates.add(mStatus);
-        mStatusChanged.signal();
+        internalUpdateStatusLocked(idle ? STATUS_CONFIGURED : STATUS_ACTIVE);
 
         // Skip notifying listener if we're doing some user-transparent
         // state changes
@@ -1649,7 +1698,7 @@
 
         // Return state to that at start of call, so that future configures
         // properly clean things up
-        mStatus = STATUS_UNCONFIGURED;
+        internalUpdateStatusLocked(STATUS_UNCONFIGURED);
         mNeedConfig = true;
 
         ALOGV("%s: Camera %d: Stream configuration failed", __FUNCTION__, mId);
@@ -1696,11 +1745,8 @@
 
     mNeedConfig = false;
 
-    if (mDummyStreamId == NO_STREAM) {
-        mStatus = STATUS_CONFIGURED;
-    } else {
-        mStatus = STATUS_UNCONFIGURED;
-    }
+    internalUpdateStatusLocked((mDummyStreamId == NO_STREAM) ?
+            STATUS_CONFIGURED : STATUS_UNCONFIGURED);
 
     ALOGV("%s: Camera %d: Stream configuration complete", __FUNCTION__, mId);
 
@@ -1808,7 +1854,7 @@
     mErrorCause = errorCause;
 
     mRequestThread->setPaused(true);
-    mStatus = STATUS_ERROR;
+    internalUpdateStatusLocked(STATUS_ERROR);
 
     // Notify upstream about a device error
     if (mListener != NULL) {
@@ -2067,8 +2113,12 @@
 
     // Sanity check - if we have too many in-flight frames, something has
     // likely gone wrong
-    if (mInFlightMap.size() > kInFlightWarnLimit) {
+    if (!mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() > kInFlightWarnLimit) {
         CLOGE("In-flight list too large: %zu", mInFlightMap.size());
+    } else if (mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() >
+            kInFlightWarnLimitHighSpeed) {
+        CLOGE("In-flight list too large for high speed configuration: %zu",
+                mInFlightMap.size());
     }
 }
 
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 140da98..5287058 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -146,6 +146,7 @@
     virtual uint32_t getDeviceVersion();
 
     virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
+    ssize_t getPointCloudBufferSize() const;
 
     // Methods called by subclasses
     void             notifyStatus(bool idle); // updates from StatusTracker
@@ -153,9 +154,11 @@
   private:
     static const size_t        kDumpLockAttempts  = 10;
     static const size_t        kDumpSleepDuration = 100000; // 0.10 sec
-    static const size_t        kInFlightWarnLimit = 20;
     static const nsecs_t       kShutdownTimeout   = 5000000000; // 5 sec
     static const nsecs_t       kActiveTimeout     = 500000000;  // 500 ms
+    static const size_t        kInFlightWarnLimit = 20;
+    static const size_t        kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8
+
     struct                     RequestTrigger;
     // minimal jpeg buffer size: 256KB + blob header
     static const ssize_t       kMinJpegBufferSize = 256 * 1024 + sizeof(camera3_jpeg_blob);
@@ -204,7 +207,11 @@
         STATUS_CONFIGURED,
         STATUS_ACTIVE
     }                          mStatus;
+
+    // Only clear mRecentStatusUpdates, mStatusWaiters from waitUntilStateThenRelock
     Vector<Status>             mRecentStatusUpdates;
+    int                        mStatusWaiters;
+
     Condition                  mStatusChanged;
 
     // Tracking cause of fatal errors when in STATUS_ERROR
@@ -275,6 +282,13 @@
     virtual CameraMetadata getLatestRequestLocked();
 
     /**
+     * Update the current device status and wake all waiting threads.
+     *
+     * Must be called with mLock held.
+     */
+    void internalUpdateStatusLocked(Status status);
+
+    /**
      * Pause processing and flush everything, but don't tell the clients.
      * This is for reconfiguring outputs transparently when according to the
      * CameraDeviceBase interface we shouldn't need to.