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.