Merge "Resolve TODOs in Vehicle HAL interface"
diff --git a/audio/2.0/IStream.hal b/audio/2.0/IStream.hal
index 5c88a69..8de7851 100644
--- a/audio/2.0/IStream.hal
+++ b/audio/2.0/IStream.hal
@@ -279,4 +279,16 @@
*/
getMmapPosition()
generates (Result retval, MmapPosition position);
+
+ /*
+ * Called by the framework to deinitialize the stream and free up
+ * all the currently allocated resources. It is recommended to close
+ * the stream on the client side as soon as it is becomes unused.
+ *
+ * @return retval OK in case the success.
+ * NOT_SUPPORTED if called on IStream instead of input or
+ * output stream interface.
+ * INVALID_STATE if the stream was already closed.
+ */
+ close() generates (Result retval);
};
diff --git a/audio/2.0/IStreamIn.hal b/audio/2.0/IStreamIn.hal
index 6cf7425..9a96f71 100644
--- a/audio/2.0/IStreamIn.hal
+++ b/audio/2.0/IStreamIn.hal
@@ -41,16 +41,45 @@
setGain(float gain) generates (Result retval);
/*
- * Read audio buffer in from driver. If at least one frame was read prior to
- * the error, 'read' must return that byte count and then return an error
- * in the subsequent call.
+ * Data structure passed back to the client via status message queue
+ * of 'read' operation.
*
- * @param size maximum amount of bytes to read.
- * @return retval operation completion status.
- * @return data audio data.
+ * Possible values of 'retval' field:
+ * - OK, read operation was successful;
+ * - INVALID_ARGUMENTS, stream was not configured properly;
+ * - INVALID_STATE, stream is in a state that doesn't allow reads.
*/
- // TODO(mnaganov): Replace with FMQ version.
- read(uint64_t size) generates (Result retval, vec<uint8_t> data);
+ struct ReadStatus {
+ Result retval;
+ uint64_t read;
+ };
+
+ /*
+ * Set up required transports for receiving audio buffers from the driver.
+ *
+ * The transport consists of two message queues: one is used for passing
+ * audio data from the driver to the client, another is used for reporting
+ * read operation status (amount of bytes actually read or error code),
+ * see ReadStatus structure definition.
+ *
+ * @param frameSize the size of a single frame, in bytes.
+ * @param framesCount the number of frames in a buffer.
+ * @param threadPriority priority of the thread that performs reads.
+ * @return retval OK if both message queues were created successfully.
+ * INVALID_STATE if the method was already called.
+ * INVALID_ARGUMENTS if there was a problem setting up
+ * the queues.
+ * @return dataMQ a message queue used for passing audio data in the format
+ * specified at the stream opening.
+ * @return statusMQ a message queue used for passing status from the driver
+ * using ReadStatus structures.
+ */
+ prepareForReading(
+ uint32_t frameSize, uint32_t framesCount,
+ ThreadPriority threadPriority)
+ generates (
+ Result retval,
+ fmq_sync<uint8_t> dataMQ, fmq_sync<ReadStatus> statusMQ);
/*
* Return the amount of input frames lost in the audio driver since the last
diff --git a/audio/2.0/IStreamOut.hal b/audio/2.0/IStreamOut.hal
index 4ba3b2f..155e329 100644
--- a/audio/2.0/IStreamOut.hal
+++ b/audio/2.0/IStreamOut.hal
@@ -44,25 +44,48 @@
setVolume(float left, float right) generates (Result retval);
/*
- * Write audio buffer to driver. On success, sets 'retval' to 'OK', and
- * returns number of bytes written. If at least one frame was written
- * successfully prior to the error, it is suggested that the driver return
- * that successful (short) byte count and then return an error in the
- * subsequent call.
+ * Data structure passed back to the client via status message queue
+ * of 'write' operation.
*
- * If 'setCallback' has previously been called to enable non-blocking mode
- * then 'write' is not allowed to block. It must write only the number of
- * bytes that currently fit in the driver/hardware buffer and then return
- * this byte count. If this is less than the requested write size the
- * callback function must be called when more space is available in the
- * driver/hardware buffer.
- *
- * @param data audio data.
- * @return retval operation completion status.
- * @return written number of bytes written.
+ * Possible values of 'retval' field:
+ * - OK, write operation was successful;
+ * - INVALID_ARGUMENTS, stream was not configured properly;
+ * - INVALID_STATE, stream is in a state that doesn't allow writes.
*/
- // TODO(mnaganov): Replace with FMQ version.
- write(vec<uint8_t> data) generates (Result retval, uint64_t written);
+ struct WriteStatus {
+ Result retval;
+ uint64_t written;
+ uint64_t frames; // presentation position
+ TimeSpec timeStamp; // presentation position
+ };
+
+ /*
+ * Set up required transports for passing audio buffers to the driver.
+ *
+ * The transport consists of two message queues: one is used for passing
+ * audio data from the client to the driver, another is used for reporting
+ * write operation status (amount of bytes actually written or error code),
+ * and the presentation position immediately after the write, see
+ * WriteStatus structure definition.
+ *
+ * @param frameSize the size of a single frame, in bytes.
+ * @param framesCount the number of frames in a buffer.
+ * @param threadPriority priority of the thread that performs writes.
+ * @return retval OK if both message queues were created successfully.
+ * INVALID_STATE if the method was already called.
+ * INVALID_ARGUMENTS if there was a problem setting up
+ * the queues.
+ * @return dataMQ a message queue used for passing audio data in the format
+ * specified at the stream opening.
+ * @return statusMQ a message queue used for passing status from the driver
+ * using WriteStatus structures.
+ */
+ prepareForWriting(
+ uint32_t frameSize, uint32_t framesCount,
+ ThreadPriority threadPriority)
+ generates (
+ Result retval,
+ fmq_sync<uint8_t> dataMQ, fmq_sync<WriteStatus> statusMQ);
/*
* Return the number of audio frames written by the audio DSP to DAC since
diff --git a/audio/2.0/default/Android.mk b/audio/2.0/default/Android.mk
index c3cfd69..eeea92c 100644
--- a/audio/2.0/default/Android.mk
+++ b/audio/2.0/default/Android.mk
@@ -30,13 +30,16 @@
StreamOut.cpp \
LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libcutils \
+ libfmq \
+ libhardware \
libhidlbase \
libhidltransport \
libhwbinder \
- libcutils \
- libutils \
- libhardware \
liblog \
+ libmediautils \
+ libutils \
android.hardware.audio@2.0 \
android.hardware.audio.common@2.0 \
android.hardware.audio.common@2.0-util \
diff --git a/audio/2.0/default/Stream.cpp b/audio/2.0/default/Stream.cpp
index f214eed..62b34a3 100644
--- a/audio/2.0/default/Stream.cpp
+++ b/audio/2.0/default/Stream.cpp
@@ -253,6 +253,10 @@
return Void();
}
+Return<Result> Stream::close() {
+ return Result::NOT_SUPPORTED;
+}
+
} // namespace implementation
} // namespace V2_0
} // namespace audio
diff --git a/audio/2.0/default/Stream.h b/audio/2.0/default/Stream.h
index 819bbf7..0bbd803 100644
--- a/audio/2.0/default/Stream.h
+++ b/audio/2.0/default/Stream.h
@@ -76,6 +76,7 @@
Return<Result> stop() override;
Return<void> createMmapBuffer(int32_t minSizeFrames, createMmapBuffer_cb _hidl_cb) override;
Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
+ Return<Result> close() override;
// Utility methods for extending interfaces.
static Result analyzeStatus(const char* funcName, int status, int ignoreError = OK);
diff --git a/audio/2.0/default/StreamIn.cpp b/audio/2.0/default/StreamIn.cpp
index 1441e74..51c2cc7 100644
--- a/audio/2.0/default/StreamIn.cpp
+++ b/audio/2.0/default/StreamIn.cpp
@@ -15,26 +15,112 @@
*/
#define LOG_TAG "StreamInHAL"
+//#define LOG_NDEBUG 0
-#include <hardware/audio.h>
#include <android/log.h>
+#include <hardware/audio.h>
+#include <mediautils/SchedulingPolicyService.h>
#include "StreamIn.h"
+using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
+
namespace android {
namespace hardware {
namespace audio {
namespace V2_0 {
namespace implementation {
+namespace {
+
+class ReadThread : public Thread {
+ public:
+ // ReadThread's lifespan never exceeds StreamIn's lifespan.
+ ReadThread(std::atomic<bool>* stop,
+ audio_stream_in_t* stream,
+ StreamIn::DataMQ* dataMQ,
+ StreamIn::StatusMQ* statusMQ,
+ EventFlag* efGroup,
+ ThreadPriority threadPriority)
+ : Thread(false /*canCallJava*/),
+ mStop(stop),
+ mStream(stream),
+ mDataMQ(dataMQ),
+ mStatusMQ(statusMQ),
+ mEfGroup(efGroup),
+ mThreadPriority(threadPriority),
+ mBuffer(new uint8_t[dataMQ->getQuantumCount()]) {
+ }
+ virtual ~ReadThread() {}
+
+ status_t readyToRun() override;
+
+ private:
+ std::atomic<bool>* mStop;
+ audio_stream_in_t* mStream;
+ StreamIn::DataMQ* mDataMQ;
+ StreamIn::StatusMQ* mStatusMQ;
+ EventFlag* mEfGroup;
+ ThreadPriority mThreadPriority;
+ std::unique_ptr<uint8_t[]> mBuffer;
+
+ bool threadLoop() override;
+};
+
+status_t ReadThread::readyToRun() {
+ if (mThreadPriority != ThreadPriority::NORMAL) {
+ int err = requestPriority(
+ getpid(), getTid(), static_cast<int>(mThreadPriority), true /*asynchronous*/);
+ ALOGW_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
+ static_cast<int>(mThreadPriority), getpid(), getTid(), err);
+ }
+ return OK;
+}
+
+bool ReadThread::threadLoop() {
+ // This implementation doesn't return control back to the Thread until it decides to stop,
+ // as the Thread uses mutexes, and this can lead to priority inversion.
+ while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
+ // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
+ uint32_t efState = 0;
+ mEfGroup->wait(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL), &efState, NS_PER_SEC);
+ if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL))) {
+ continue; // Nothing to do.
+ }
+
+ const size_t availToWrite = mDataMQ->availableToWrite();
+ ssize_t readResult = mStream->read(mStream, &mBuffer[0], availToWrite);
+ Result retval = Result::OK;
+ uint64_t read = 0;
+ if (readResult >= 0) {
+ read = readResult;
+ if (!mDataMQ->write(&mBuffer[0], readResult)) {
+ ALOGW("data message queue write failed");
+ }
+ } else {
+ retval = Stream::analyzeStatus("read", readResult);
+ }
+ IStreamIn::ReadStatus status = { retval, read };
+ if (!mStatusMQ->write(&status)) {
+ ALOGW("status message queue write failed");
+ }
+ mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
+ }
+
+ return false;
+}
+
+} // namespace
+
StreamIn::StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream)
- : mDevice(device), mStream(stream),
+ : mIsClosed(false), mDevice(device), mStream(stream),
mStreamCommon(new Stream(&stream->common)),
- mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)) {
+ mStreamMmap(new StreamMmap<audio_stream_in_t>(stream)),
+ mEfGroup(nullptr), mStopReadThread(false) {
}
StreamIn::~StreamIn() {
- mDevice->close_input_stream(mDevice, mStream);
+ close();
mStream = nullptr;
mDevice = nullptr;
}
@@ -149,6 +235,22 @@
return mStreamMmap->getMmapPosition(_hidl_cb);
}
+Return<Result> StreamIn::close() {
+ if (mIsClosed) return Result::INVALID_STATE;
+ mIsClosed = true;
+ if (mReadThread.get()) {
+ mStopReadThread.store(true, std::memory_order_release);
+ status_t status = mReadThread->requestExitAndWait();
+ ALOGE_IF(status, "read thread exit error: %s", strerror(-status));
+ }
+ if (mEfGroup) {
+ status_t status = EventFlag::deleteEventFlag(&mEfGroup);
+ ALOGE_IF(status, "read MQ event flag deletion error: %s", strerror(-status));
+ }
+ mDevice->close_input_stream(mDevice, mStream);
+ return Result::OK;
+}
+
// Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
Return<void> StreamIn::getAudioSource(getAudioSource_cb _hidl_cb) {
int halSource;
@@ -165,19 +267,55 @@
return Stream::analyzeStatus("set_gain", mStream->set_gain(mStream, gain));
}
-Return<void> StreamIn::read(uint64_t size, read_cb _hidl_cb) {
- // TODO(mnaganov): Replace with FMQ version.
- hidl_vec<uint8_t> data;
- data.resize(size);
- Result retval(Result::OK);
- ssize_t readResult = mStream->read(mStream, &data[0], data.size());
- if (readResult >= 0 && static_cast<size_t>(readResult) != data.size()) {
- data.resize(readResult);
- } else if (readResult < 0) {
- data.resize(0);
- retval = Stream::analyzeStatus("read", readResult);
+Return<void> StreamIn::prepareForReading(
+ uint32_t frameSize, uint32_t framesCount, ThreadPriority threadPriority,
+ prepareForReading_cb _hidl_cb) {
+ status_t status;
+ // Create message queues.
+ if (mDataMQ) {
+ ALOGE("the client attempts to call prepareForReading twice");
+ _hidl_cb(Result::INVALID_STATE,
+ MQDescriptorSync<uint8_t>(), MQDescriptorSync<ReadStatus>());
+ return Void();
}
- _hidl_cb(retval, data);
+ std::unique_ptr<DataMQ> tempDataMQ(
+ new DataMQ(frameSize * framesCount, true /* EventFlag */));
+ std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
+ if (!tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
+ ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
+ ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ MQDescriptorSync<uint8_t>(), MQDescriptorSync<ReadStatus>());
+ return Void();
+ }
+ // TODO: Remove event flag management once blocking MQ is implemented. b/33815422
+ status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
+ if (status != OK || !mEfGroup) {
+ ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ MQDescriptorSync<uint8_t>(), MQDescriptorSync<ReadStatus>());
+ return Void();
+ }
+
+ // Create and launch the thread.
+ mReadThread = new ReadThread(
+ &mStopReadThread,
+ mStream,
+ tempDataMQ.get(),
+ tempStatusMQ.get(),
+ mEfGroup,
+ threadPriority);
+ status = mReadThread->run("reader", PRIORITY_URGENT_AUDIO);
+ if (status != OK) {
+ ALOGW("failed to start reader thread: %s", strerror(-status));
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ MQDescriptorSync<uint8_t>(), MQDescriptorSync<ReadStatus>());
+ return Void();
+ }
+
+ mDataMQ = std::move(tempDataMQ);
+ mStatusMQ = std::move(tempStatusMQ);
+ _hidl_cb(Result::OK, *mDataMQ->getDesc(), *mStatusMQ->getDesc());
return Void();
}
diff --git a/audio/2.0/default/StreamIn.h b/audio/2.0/default/StreamIn.h
index 65e94bb..fc813d9 100644
--- a/audio/2.0/default/StreamIn.h
+++ b/audio/2.0/default/StreamIn.h
@@ -17,10 +17,15 @@
#ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMIN_H
-#include <android/hardware/audio/2.0/IStreamIn.h>
-#include <hidl/Status.h>
+#include <atomic>
+#include <memory>
+#include <android/hardware/audio/2.0/IStreamIn.h>
#include <hidl/MQDescriptor.h>
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/Status.h>
+#include <utils/Thread.h>
#include "Stream.h"
@@ -39,6 +44,7 @@
using ::android::hardware::audio::V2_0::IStreamIn;
using ::android::hardware::audio::V2_0::ParameterValue;
using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::audio::V2_0::ThreadPriority;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
@@ -46,6 +52,9 @@
using ::android::sp;
struct StreamIn : public IStreamIn {
+ typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
+ typedef MessageQueue<ReadStatus, kSynchronizedReadWrite> StatusMQ;
+
StreamIn(audio_hw_device_t* device, audio_stream_in_t* stream);
// Methods from ::android::hardware::audio::V2_0::IStream follow.
@@ -73,11 +82,14 @@
const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override;
Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
Return<void> debugDump(const hidl_handle& fd) override;
+ Return<Result> close() override;
// Methods from ::android::hardware::audio::V2_0::IStreamIn follow.
Return<void> getAudioSource(getAudioSource_cb _hidl_cb) override;
Return<Result> setGain(float gain) override;
- Return<void> read(uint64_t size, read_cb _hidl_cb) override;
+ Return<void> prepareForReading(
+ uint32_t frameSize, uint32_t framesCount, ThreadPriority threadPriority,
+ prepareForReading_cb _hidl_cb) override;
Return<uint32_t> getInputFramesLost() override;
Return<void> getCapturePosition(getCapturePosition_cb _hidl_cb) override;
Return<Result> start() override;
@@ -86,11 +98,16 @@
Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
private:
+ bool mIsClosed;
audio_hw_device_t *mDevice;
audio_stream_in_t *mStream;
sp<Stream> mStreamCommon;
sp<StreamMmap<audio_stream_in_t>> mStreamMmap;
-
+ std::unique_ptr<DataMQ> mDataMQ;
+ std::unique_ptr<StatusMQ> mStatusMQ;
+ EventFlag* mEfGroup;
+ std::atomic<bool> mStopReadThread;
+ sp<Thread> mReadThread;
virtual ~StreamIn();
};
diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp
index 3d20d11..4bb2274 100644
--- a/audio/2.0/default/StreamOut.cpp
+++ b/audio/2.0/default/StreamOut.cpp
@@ -17,8 +17,9 @@
#define LOG_TAG "StreamOutHAL"
//#define LOG_NDEBUG 0
-#include <hardware/audio.h>
#include <android/log.h>
+#include <hardware/audio.h>
+#include <mediautils/SchedulingPolicyService.h>
#include "StreamOut.h"
@@ -28,15 +29,103 @@
namespace V2_0 {
namespace implementation {
+namespace {
+
+class WriteThread : public Thread {
+ public:
+ // WriteThread's lifespan never exceeds StreamOut's lifespan.
+ WriteThread(std::atomic<bool>* stop,
+ audio_stream_out_t* stream,
+ StreamOut::DataMQ* dataMQ,
+ StreamOut::StatusMQ* statusMQ,
+ EventFlag* efGroup,
+ ThreadPriority threadPriority)
+ : Thread(false /*canCallJava*/),
+ mStop(stop),
+ mStream(stream),
+ mDataMQ(dataMQ),
+ mStatusMQ(statusMQ),
+ mEfGroup(efGroup),
+ mThreadPriority(threadPriority),
+ mBuffer(new uint8_t[dataMQ->getQuantumCount()]) {
+ }
+ virtual ~WriteThread() {}
+
+ status_t readyToRun() override;
+
+ private:
+ std::atomic<bool>* mStop;
+ audio_stream_out_t* mStream;
+ StreamOut::DataMQ* mDataMQ;
+ StreamOut::StatusMQ* mStatusMQ;
+ EventFlag* mEfGroup;
+ ThreadPriority mThreadPriority;
+ std::unique_ptr<uint8_t[]> mBuffer;
+
+ bool threadLoop() override;
+};
+
+status_t WriteThread::readyToRun() {
+ if (mThreadPriority != ThreadPriority::NORMAL) {
+ int err = requestPriority(
+ getpid(), getTid(), static_cast<int>(mThreadPriority), true /*asynchronous*/);
+ ALOGW_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
+ static_cast<int>(mThreadPriority), getpid(), getTid(), err);
+ }
+ return OK;
+}
+
+bool WriteThread::threadLoop() {
+ // This implementation doesn't return control back to the Thread until it decides to stop,
+ // as the Thread uses mutexes, and this can lead to priority inversion.
+ while(!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
+ // TODO: Remove manual event flag handling once blocking MQ is implemented. b/33815422
+ uint32_t efState = 0;
+ mEfGroup->wait(
+ static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY), &efState, NS_PER_SEC);
+ if (!(efState & static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY))) {
+ continue; // Nothing to do.
+ }
+
+ const size_t availToRead = mDataMQ->availableToRead();
+ Result retval = Result::OK;
+ uint64_t written = 0;
+ if (mDataMQ->read(&mBuffer[0], availToRead)) {
+ ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);
+ if (writeResult >= 0) {
+ written = writeResult;
+ } else {
+ retval = Stream::analyzeStatus("write", writeResult);
+ }
+ }
+ uint64_t frames = 0;
+ struct timespec halTimeStamp = { 0, 0 };
+ if (retval == Result::OK && mStream->get_presentation_position != NULL) {
+ mStream->get_presentation_position(mStream, &frames, &halTimeStamp);
+ }
+ IStreamOut::WriteStatus status = { retval, written, frames,
+ { static_cast<uint64_t>(halTimeStamp.tv_sec),
+ static_cast<uint64_t>(halTimeStamp.tv_nsec) } };
+ if (!mStatusMQ->write(&status)) {
+ ALOGW("status message queue write failed");
+ }
+ mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_FULL));
+ }
+
+ return false;
+}
+
+} // namespace
+
StreamOut::StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream)
- : mDevice(device), mStream(stream),
+ : mIsClosed(false), mDevice(device), mStream(stream),
mStreamCommon(new Stream(&stream->common)),
- mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)) {
+ mStreamMmap(new StreamMmap<audio_stream_out_t>(stream)),
+ mEfGroup(nullptr), mStopWriteThread(false) {
}
StreamOut::~StreamOut() {
- mCallback.clear();
- mDevice->close_output_stream(mDevice, mStream);
+ close();
mStream = nullptr;
mDevice = nullptr;
}
@@ -135,6 +224,23 @@
return mStreamCommon->debugDump(fd);
}
+Return<Result> StreamOut::close() {
+ if (mIsClosed) return Result::INVALID_STATE;
+ mIsClosed = true;
+ if (mWriteThread.get()) {
+ mStopWriteThread.store(true, std::memory_order_release);
+ status_t status = mWriteThread->requestExitAndWait();
+ ALOGE_IF(status, "write thread exit error: %s", strerror(-status));
+ }
+ if (mEfGroup) {
+ status_t status = EventFlag::deleteEventFlag(&mEfGroup);
+ ALOGE_IF(status, "write MQ event flag deletion error: %s", strerror(-status));
+ }
+ mCallback.clear();
+ mDevice->close_output_stream(mDevice, mStream);
+ return Result::OK;
+}
+
// Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
Return<uint32_t> StreamOut::getLatency() {
return mStream->get_latency(mStream);
@@ -149,18 +255,55 @@
return retval;
}
-Return<void> StreamOut::write(const hidl_vec<uint8_t>& data, write_cb _hidl_cb) {
- // TODO(mnaganov): Replace with FMQ version.
- Result retval(Result::OK);
- uint64_t written = 0;
- ssize_t writeResult = mStream->write(mStream, &data[0], data.size());
- if (writeResult >= 0) {
- written = writeResult;
- } else {
- retval = Stream::analyzeStatus("write", writeResult);
- written = 0;
+Return<void> StreamOut::prepareForWriting(
+ uint32_t frameSize, uint32_t framesCount, ThreadPriority threadPriority,
+ prepareForWriting_cb _hidl_cb) {
+ status_t status;
+ // Create message queues.
+ if (mDataMQ) {
+ ALOGE("the client attempts to call prepareForWriting twice");
+ _hidl_cb(Result::INVALID_STATE,
+ MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>());
+ return Void();
}
- _hidl_cb(retval, written);
+ std::unique_ptr<DataMQ> tempDataMQ(
+ new DataMQ(frameSize * framesCount, true /* EventFlag */));
+ std::unique_ptr<StatusMQ> tempStatusMQ(new StatusMQ(1));
+ if (!tempDataMQ->isValid() || !tempStatusMQ->isValid()) {
+ ALOGE_IF(!tempDataMQ->isValid(), "data MQ is invalid");
+ ALOGE_IF(!tempStatusMQ->isValid(), "status MQ is invalid");
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>());
+ return Void();
+ }
+ // TODO: Remove event flag management once blocking MQ is implemented. b/33815422
+ status = EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
+ if (status != OK || !mEfGroup) {
+ ALOGE("failed creating event flag for data MQ: %s", strerror(-status));
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>());
+ return Void();
+ }
+
+ // Create and launch the thread.
+ mWriteThread = new WriteThread(
+ &mStopWriteThread,
+ mStream,
+ tempDataMQ.get(),
+ tempStatusMQ.get(),
+ mEfGroup,
+ threadPriority);
+ status = mWriteThread->run("writer", PRIORITY_URGENT_AUDIO);
+ if (status != OK) {
+ ALOGW("failed to start writer thread: %s", strerror(-status));
+ _hidl_cb(Result::INVALID_ARGUMENTS,
+ MQDescriptorSync<uint8_t>(), MQDescriptorSync<WriteStatus>());
+ return Void();
+ }
+
+ mDataMQ = std::move(tempDataMQ);
+ mStatusMQ = std::move(tempStatusMQ);
+ _hidl_cb(Result::OK, *mDataMQ->getDesc(), *mStatusMQ->getDesc());
return Void();
}
diff --git a/audio/2.0/default/StreamOut.h b/audio/2.0/default/StreamOut.h
index 9b7f9f8..83f4447 100644
--- a/audio/2.0/default/StreamOut.h
+++ b/audio/2.0/default/StreamOut.h
@@ -17,10 +17,15 @@
#ifndef ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
#define ANDROID_HARDWARE_AUDIO_V2_0_STREAMOUT_H
-#include <android/hardware/audio/2.0/IStreamOut.h>
-#include <hidl/Status.h>
+#include <atomic>
+#include <memory>
+#include <android/hardware/audio/2.0/IStreamOut.h>
#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <fmq/EventFlag.h>
+#include <fmq/MessageQueue.h>
+#include <utils/Thread.h>
#include "Stream.h"
@@ -40,6 +45,7 @@
using ::android::hardware::audio::V2_0::IStreamOutCallback;
using ::android::hardware::audio::V2_0::ParameterValue;
using ::android::hardware::audio::V2_0::Result;
+using ::android::hardware::audio::V2_0::ThreadPriority;
using ::android::hardware::audio::V2_0::TimeSpec;
using ::android::hardware::Return;
using ::android::hardware::Void;
@@ -48,6 +54,9 @@
using ::android::sp;
struct StreamOut : public IStreamOut {
+ typedef MessageQueue<uint8_t, kSynchronizedReadWrite> DataMQ;
+ typedef MessageQueue<WriteStatus, kSynchronizedReadWrite> StatusMQ;
+
StreamOut(audio_hw_device_t* device, audio_stream_out_t* stream);
// Methods from ::android::hardware::audio::V2_0::IStream follow.
@@ -75,11 +84,14 @@
const hidl_vec<hidl_string>& keys, getParameters_cb _hidl_cb) override;
Return<Result> setParameters(const hidl_vec<ParameterValue>& parameters) override;
Return<void> debugDump(const hidl_handle& fd) override;
+ Return<Result> close() override;
// Methods from ::android::hardware::audio::V2_0::IStreamOut follow.
Return<uint32_t> getLatency() override;
Return<Result> setVolume(float left, float right) override;
- Return<void> write(const hidl_vec<uint8_t>& data, write_cb _hidl_cb) override;
+ Return<void> prepareForWriting(
+ uint32_t frameSize, uint32_t framesCount, ThreadPriority threadPriority,
+ prepareForWriting_cb _hidl_cb) override;
Return<void> getRenderPosition(getRenderPosition_cb _hidl_cb) override;
Return<void> getNextWriteTimestamp(getNextWriteTimestamp_cb _hidl_cb) override;
Return<Result> setCallback(const sp<IStreamOutCallback>& callback) override;
@@ -97,11 +109,17 @@
Return<void> getMmapPosition(getMmapPosition_cb _hidl_cb) override;
private:
+ bool mIsClosed;
audio_hw_device_t *mDevice;
audio_stream_out_t *mStream;
sp<Stream> mStreamCommon;
sp<StreamMmap<audio_stream_out_t>> mStreamMmap;
sp<IStreamOutCallback> mCallback;
+ std::unique_ptr<DataMQ> mDataMQ;
+ std::unique_ptr<StatusMQ> mStatusMQ;
+ EventFlag* mEfGroup;
+ std::atomic<bool> mStopWriteThread;
+ sp<Thread> mWriteThread;
virtual ~StreamOut();
diff --git a/audio/2.0/types.hal b/audio/2.0/types.hal
index 37c39e4..8fc4314 100644
--- a/audio/2.0/types.hal
+++ b/audio/2.0/types.hal
@@ -89,3 +89,21 @@
int64_t timeNanoseconds; // time stamp in ns, CLOCK_MONOTONIC
int32_t positionFrames; // increasing 32 bit frame count reset when IStream.stop() is called
};
+
+/*
+ * The message queue flags used to synchronize reads and writes from
+ * message queues used by StreamIn and StreamOut.
+ */
+enum MessageQueueFlagBits : uint32_t {
+ NOT_EMPTY = 1 << 0,
+ NOT_FULL = 1 << 1
+};
+
+/*
+ * The priority of threads executing reads and writes of audio data.
+ */
+enum ThreadPriority : int32_t {
+ NORMAL = 0,
+ FAST_CAPTURE = 3,
+ FAST_MIXER = 3
+};
diff --git a/camera/Android.bp b/camera/Android.bp
index a373bf4..e379e49 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -1,8 +1,12 @@
// This is an autogenerated file, do not edit.
subdirs = [
"common/1.0",
+ "common/1.0/default",
"device/1.0",
"device/3.2",
+ "device/3.2/default",
"metadata/3.2",
"provider/2.4",
+ "provider/2.4/default",
+ "provider/2.4/vts/functional",
]
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
new file mode 100644
index 0000000..af0ff6e
--- /dev/null
+++ b/camera/common/1.0/default/Android.bp
@@ -0,0 +1,15 @@
+cc_library_static {
+ name: "android.hardware.camera.common@1.0-helper",
+ srcs: ["CameraModule.cpp", "CameraMetadata.cpp", "VendorTagDescriptor.cpp"],
+ cflags: [
+ "-Werror",
+ "-Wextra",
+ "-Wall",
+ ],
+ shared_libs: [
+ "liblog",
+ "libhardware",
+ "libcamera_metadata"],
+ include_dirs: ["system/media/private/camera/include"],
+ export_include_dirs : ["include"]
+}
diff --git a/camera/common/1.0/default/CameraMetadata.cpp b/camera/common/1.0/default/CameraMetadata.cpp
new file mode 100644
index 0000000..44c2040
--- /dev/null
+++ b/camera/common/1.0/default/CameraMetadata.cpp
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+
+#define LOG_TAG "CamComm1.0-MD"
+#include <utils/Log.h>
+#include <utils/Errors.h>
+
+#include "CameraMetadata.h"
+#include "VendorTagDescriptor.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+#define ALIGN_TO(val, alignment) \
+ (((uintptr_t)(val) + ((alignment) - 1)) & ~((alignment) - 1))
+
+CameraMetadata::CameraMetadata() :
+ mBuffer(NULL), mLocked(false) {
+}
+
+CameraMetadata::CameraMetadata(size_t entryCapacity, size_t dataCapacity) :
+ mLocked(false)
+{
+ mBuffer = allocate_camera_metadata(entryCapacity, dataCapacity);
+}
+
+CameraMetadata::CameraMetadata(const CameraMetadata &other) :
+ mLocked(false) {
+ mBuffer = clone_camera_metadata(other.mBuffer);
+}
+
+CameraMetadata::CameraMetadata(camera_metadata_t *buffer) :
+ mBuffer(NULL), mLocked(false) {
+ acquire(buffer);
+}
+
+CameraMetadata &CameraMetadata::operator=(const CameraMetadata &other) {
+ return operator=(other.mBuffer);
+}
+
+CameraMetadata &CameraMetadata::operator=(const camera_metadata_t *buffer) {
+ if (mLocked) {
+ ALOGE("%s: Assignment to a locked CameraMetadata!", __FUNCTION__);
+ return *this;
+ }
+
+ if (CC_LIKELY(buffer != mBuffer)) {
+ camera_metadata_t *newBuffer = clone_camera_metadata(buffer);
+ clear();
+ mBuffer = newBuffer;
+ }
+ return *this;
+}
+
+CameraMetadata::~CameraMetadata() {
+ mLocked = false;
+ clear();
+}
+
+const camera_metadata_t* CameraMetadata::getAndLock() const {
+ mLocked = true;
+ return mBuffer;
+}
+
+status_t CameraMetadata::unlock(const camera_metadata_t *buffer) const {
+ if (!mLocked) {
+ ALOGE("%s: Can't unlock a non-locked CameraMetadata!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (buffer != mBuffer) {
+ ALOGE("%s: Can't unlock CameraMetadata with wrong pointer!",
+ __FUNCTION__);
+ return BAD_VALUE;
+ }
+ mLocked = false;
+ return OK;
+}
+
+camera_metadata_t* CameraMetadata::release() {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return NULL;
+ }
+ camera_metadata_t *released = mBuffer;
+ mBuffer = NULL;
+ return released;
+}
+
+void CameraMetadata::clear() {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return;
+ }
+ if (mBuffer) {
+ free_camera_metadata(mBuffer);
+ mBuffer = NULL;
+ }
+}
+
+void CameraMetadata::acquire(camera_metadata_t *buffer) {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return;
+ }
+ 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) {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return;
+ }
+ acquire(other.release());
+}
+
+status_t CameraMetadata::append(const CameraMetadata &other) {
+ return append(other.mBuffer);
+}
+
+status_t CameraMetadata::append(const camera_metadata_t* other) {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ size_t extraEntries = get_camera_metadata_entry_count(other);
+ size_t extraData = get_camera_metadata_data_count(other);
+ resizeIfNeeded(extraEntries, extraData);
+
+ return append_camera_metadata(mBuffer, other);
+}
+
+size_t CameraMetadata::entryCount() const {
+ return (mBuffer == NULL) ? 0 :
+ get_camera_metadata_entry_count(mBuffer);
+}
+
+bool CameraMetadata::isEmpty() const {
+ return entryCount() == 0;
+}
+
+status_t CameraMetadata::sort() {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ return sort_camera_metadata(mBuffer);
+}
+
+status_t CameraMetadata::checkType(uint32_t tag, uint8_t expectedType) {
+ int tagType = get_camera_metadata_tag_type(tag);
+ if ( CC_UNLIKELY(tagType == -1)) {
+ ALOGE("Update metadata entry: Unknown tag %d", tag);
+ return INVALID_OPERATION;
+ }
+ if ( CC_UNLIKELY(tagType != expectedType) ) {
+ ALOGE("Mismatched tag type when updating entry %s (%d) of type %s; "
+ "got type %s data instead ",
+ get_camera_metadata_tag_name(tag), tag,
+ camera_metadata_type_names[tagType],
+ camera_metadata_type_names[expectedType]);
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const int32_t *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_INT32)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const uint8_t *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const float *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_FLOAT)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const int64_t *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_INT64)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const double *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_DOUBLE)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const camera_metadata_rational_t *data, size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_RATIONAL)) != OK) {
+ return res;
+ }
+ return updateImpl(tag, (const void*)data, data_count);
+}
+
+status_t CameraMetadata::update(uint32_t tag,
+ const String8 &string) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(tag, TYPE_BYTE)) != OK) {
+ return res;
+ }
+ // string.size() doesn't count the null termination character.
+ return updateImpl(tag, (const void*)string.string(), string.size() + 1);
+}
+
+status_t CameraMetadata::update(const camera_metadata_ro_entry &entry) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if ( (res = checkType(entry.tag, entry.type)) != OK) {
+ return res;
+ }
+ return updateImpl(entry.tag, (const void*)entry.data.u8, entry.count);
+}
+
+status_t CameraMetadata::updateImpl(uint32_t tag, const void *data,
+ size_t data_count) {
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ int type = get_camera_metadata_tag_type(tag);
+ if (type == -1) {
+ ALOGE("%s: Tag %d not found", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+ // Safety check - ensure that data isn't pointing to this metadata, since
+ // that would get invalidated if a resize is needed
+ size_t bufferSize = get_camera_metadata_size(mBuffer);
+ uintptr_t bufAddr = reinterpret_cast<uintptr_t>(mBuffer);
+ uintptr_t dataAddr = reinterpret_cast<uintptr_t>(data);
+ if (dataAddr > bufAddr && dataAddr < (bufAddr + bufferSize)) {
+ ALOGE("%s: Update attempted with data from the same metadata buffer!",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ size_t data_size = calculate_camera_metadata_entry_data_size(type,
+ data_count);
+
+ res = resizeIfNeeded(1, data_size);
+
+ if (res == OK) {
+ camera_metadata_entry_t entry;
+ res = find_camera_metadata_entry(mBuffer, tag, &entry);
+ if (res == NAME_NOT_FOUND) {
+ res = add_camera_metadata_entry(mBuffer,
+ tag, data, data_count);
+ } else if (res == OK) {
+ res = update_camera_metadata_entry(mBuffer,
+ entry.index, data, data_count, NULL);
+ }
+ }
+
+ if (res != OK) {
+ ALOGE("%s: Unable to update metadata entry %s.%s (%x): %s (%d)",
+ __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;
+}
+
+bool CameraMetadata::exists(uint32_t tag) const {
+ camera_metadata_ro_entry entry;
+ return find_camera_metadata_ro_entry(mBuffer, tag, &entry) == 0;
+}
+
+camera_metadata_entry_t CameraMetadata::find(uint32_t tag) {
+ status_t res;
+ camera_metadata_entry entry;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ entry.count = 0;
+ return entry;
+ }
+ res = find_camera_metadata_entry(mBuffer, tag, &entry);
+ if (CC_UNLIKELY( res != OK )) {
+ entry.count = 0;
+ entry.data.u8 = NULL;
+ }
+ return entry;
+}
+
+camera_metadata_ro_entry_t CameraMetadata::find(uint32_t tag) const {
+ status_t res;
+ camera_metadata_ro_entry entry;
+ res = find_camera_metadata_ro_entry(mBuffer, tag, &entry);
+ if (CC_UNLIKELY( res != OK )) {
+ entry.count = 0;
+ entry.data.u8 = NULL;
+ }
+ return entry;
+}
+
+status_t CameraMetadata::erase(uint32_t tag) {
+ camera_metadata_entry_t entry;
+ status_t res;
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ res = find_camera_metadata_entry(mBuffer, tag, &entry);
+ if (res == NAME_NOT_FOUND) {
+ return OK;
+ } else if (res != OK) {
+ ALOGE("%s: Error looking for entry %s.%s (%x): %s %d",
+ __FUNCTION__,
+ get_camera_metadata_section_name(tag),
+ get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+ return res;
+ }
+ res = delete_camera_metadata_entry(mBuffer, entry.index);
+ if (res != OK) {
+ ALOGE("%s: Error deleting entry %s.%s (%x): %s %d",
+ __FUNCTION__,
+ get_camera_metadata_section_name(tag),
+ get_camera_metadata_tag_name(tag), tag, strerror(-res), res);
+ }
+ return res;
+}
+
+void CameraMetadata::dump(int fd, int verbosity, int indentation) const {
+ dump_indented_camera_metadata(mBuffer, fd, verbosity, indentation);
+}
+
+status_t CameraMetadata::resizeIfNeeded(size_t extraEntries, size_t extraData) {
+ if (mBuffer == NULL) {
+ mBuffer = allocate_camera_metadata(extraEntries * 2, extraData * 2);
+ if (mBuffer == NULL) {
+ ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
+ return NO_MEMORY;
+ }
+ } else {
+ size_t currentEntryCount = get_camera_metadata_entry_count(mBuffer);
+ size_t currentEntryCap = get_camera_metadata_entry_capacity(mBuffer);
+ size_t newEntryCount = currentEntryCount +
+ extraEntries;
+ newEntryCount = (newEntryCount > currentEntryCap) ?
+ newEntryCount * 2 : currentEntryCap;
+
+ size_t currentDataCount = get_camera_metadata_data_count(mBuffer);
+ size_t currentDataCap = get_camera_metadata_data_capacity(mBuffer);
+ size_t newDataCount = currentDataCount +
+ extraData;
+ newDataCount = (newDataCount > currentDataCap) ?
+ newDataCount * 2 : currentDataCap;
+
+ if (newEntryCount > currentEntryCap ||
+ newDataCount > currentDataCap) {
+ camera_metadata_t *oldBuffer = mBuffer;
+ mBuffer = allocate_camera_metadata(newEntryCount,
+ newDataCount);
+ if (mBuffer == NULL) {
+ ALOGE("%s: Can't allocate larger metadata buffer", __FUNCTION__);
+ return NO_MEMORY;
+ }
+ append_camera_metadata(mBuffer, oldBuffer);
+ free_camera_metadata(oldBuffer);
+ }
+ }
+ return OK;
+}
+
+void CameraMetadata::swap(CameraMetadata& other) {
+ if (mLocked) {
+ ALOGE("%s: CameraMetadata is locked", __FUNCTION__);
+ return;
+ } else if (other.mLocked) {
+ ALOGE("%s: Other CameraMetadata is locked", __FUNCTION__);
+ return;
+ }
+
+ camera_metadata* thisBuf = mBuffer;
+ camera_metadata* otherBuf = other.mBuffer;
+
+ other.mBuffer = thisBuf;
+ mBuffer = otherBuf;
+}
+
+status_t CameraMetadata::getTagFromName(const char *name,
+ const VendorTagDescriptor* vTags, uint32_t *tag) {
+
+ if (name == nullptr || tag == nullptr) return BAD_VALUE;
+
+ size_t nameLength = strlen(name);
+
+ const SortedVector<String8> *vendorSections;
+ size_t vendorSectionCount = 0;
+
+ if (vTags != NULL) {
+ vendorSections = vTags->getAllSectionNames();
+ vendorSectionCount = vendorSections->size();
+ }
+
+ // First, find the section by the longest string match
+ const char *section = NULL;
+ size_t sectionIndex = 0;
+ size_t sectionLength = 0;
+ size_t totalSectionCount = ANDROID_SECTION_COUNT + vendorSectionCount;
+ for (size_t i = 0; i < totalSectionCount; ++i) {
+
+ const char *str = (i < ANDROID_SECTION_COUNT) ? camera_metadata_section_names[i] :
+ (*vendorSections)[i - ANDROID_SECTION_COUNT].string();
+
+ ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
+
+ if (strstr(name, str) == name) { // name begins with the section name
+ size_t strLength = strlen(str);
+
+ ALOGV("%s: Name begins with section name", __FUNCTION__);
+
+ // section name is the longest we've found so far
+ if (section == NULL || sectionLength < strLength) {
+ section = str;
+ sectionIndex = i;
+ sectionLength = strLength;
+
+ ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
+ }
+ }
+ }
+
+ // TODO: Make above get_camera_metadata_section_from_name ?
+
+ if (section == NULL) {
+ return NAME_NOT_FOUND;
+ } else {
+ ALOGV("%s: Found matched section '%s' (%zu)",
+ __FUNCTION__, section, sectionIndex);
+ }
+
+ // Get the tag name component of the name
+ const char *nameTagName = name + sectionLength + 1; // x.y.z -> z
+ if (sectionLength + 1 >= nameLength) {
+ return BAD_VALUE;
+ }
+
+ // Match rest of name against the tag names in that section only
+ uint32_t candidateTag = 0;
+ if (sectionIndex < ANDROID_SECTION_COUNT) {
+ // Match built-in tags (typically android.*)
+ uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
+ tagBegin = camera_metadata_section_bounds[sectionIndex][0];
+ tagEnd = camera_metadata_section_bounds[sectionIndex][1];
+
+ for (candidateTag = tagBegin; candidateTag < tagEnd; ++candidateTag) {
+ const char *tagName = get_camera_metadata_tag_name(candidateTag);
+
+ if (strcmp(nameTagName, tagName) == 0) {
+ ALOGV("%s: Found matched tag '%s' (%d)",
+ __FUNCTION__, tagName, candidateTag);
+ break;
+ }
+ }
+
+ if (candidateTag == tagEnd) {
+ return NAME_NOT_FOUND;
+ }
+ } else if (vTags != NULL) {
+ // Match vendor tags (typically com.*)
+ const String8 sectionName(section);
+ const String8 tagName(nameTagName);
+
+ status_t res = OK;
+ if ((res = vTags->lookupTag(tagName, sectionName, &candidateTag)) != OK) {
+ return NAME_NOT_FOUND;
+ }
+ }
+
+ *tag = candidateTag;
+ return OK;
+}
+
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
new file mode 100644
index 0000000..5d9ae4d
--- /dev/null
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamComm1.0-CamModule"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Trace.h>
+
+#include "CameraModule.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+void CameraModule::deriveCameraCharacteristicsKeys(
+ uint32_t deviceVersion, CameraMetadata &chars) {
+ ATRACE_CALL();
+
+ Vector<int32_t> derivedCharKeys;
+ Vector<int32_t> derivedRequestKeys;
+ Vector<int32_t> derivedResultKeys;
+ // Keys added in HAL3.3
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) {
+ Vector<uint8_t> controlModes;
+ uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
+ chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1);
+ data = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE;
+ chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/1);
+ controlModes.push(ANDROID_CONTROL_MODE_AUTO);
+ camera_metadata_entry entry = chars.find(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
+ if (entry.count > 1 || entry.data.u8[0] != ANDROID_CONTROL_SCENE_MODE_DISABLED) {
+ controlModes.push(ANDROID_CONTROL_MODE_USE_SCENE_MODE);
+ }
+
+ // Only advertise CONTROL_OFF mode if 3A manual controls are supported.
+ bool isManualAeSupported = false;
+ bool isManualAfSupported = false;
+ bool isManualAwbSupported = false;
+ entry = chars.find(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+ if (entry.count > 0) {
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == ANDROID_CONTROL_AE_MODE_OFF) {
+ isManualAeSupported = true;
+ break;
+ }
+ }
+ }
+ entry = chars.find(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+ if (entry.count > 0) {
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == ANDROID_CONTROL_AF_MODE_OFF) {
+ isManualAfSupported = true;
+ break;
+ }
+ }
+ }
+ entry = chars.find(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+ if (entry.count > 0) {
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == ANDROID_CONTROL_AWB_MODE_OFF) {
+ isManualAwbSupported = true;
+ break;
+ }
+ }
+ }
+ if (isManualAeSupported && isManualAfSupported && isManualAwbSupported) {
+ controlModes.push(ANDROID_CONTROL_MODE_OFF);
+ }
+
+ chars.update(ANDROID_CONTROL_AVAILABLE_MODES, controlModes);
+
+ entry = chars.find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS);
+ // HAL3.2 devices passing existing CTS test should all support all LSC modes and LSC map
+ bool lensShadingModeSupported = false;
+ if (entry.count > 0) {
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.i32[i] == ANDROID_SHADING_MODE) {
+ lensShadingModeSupported = true;
+ break;
+ }
+ }
+ }
+ Vector<uint8_t> lscModes;
+ Vector<uint8_t> lscMapModes;
+ lscModes.push(ANDROID_SHADING_MODE_FAST);
+ lscModes.push(ANDROID_SHADING_MODE_HIGH_QUALITY);
+ lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);
+ if (lensShadingModeSupported) {
+ lscModes.push(ANDROID_SHADING_MODE_OFF);
+ lscMapModes.push(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_ON);
+ }
+ chars.update(ANDROID_SHADING_AVAILABLE_MODES, lscModes);
+ chars.update(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, lscMapModes);
+
+ derivedCharKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
+ derivedCharKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE);
+ derivedCharKeys.push(ANDROID_CONTROL_AVAILABLE_MODES);
+ derivedCharKeys.push(ANDROID_SHADING_AVAILABLE_MODES);
+ derivedCharKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES);
+
+ // Need update android.control.availableHighSpeedVideoConfigurations since HAL3.3
+ // adds batch size to this array.
+ entry = chars.find(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
+ if (entry.count > 0) {
+ Vector<int32_t> highSpeedConfig;
+ for (size_t i = 0; i < entry.count; i += 4) {
+ highSpeedConfig.add(entry.data.i32[i]); // width
+ highSpeedConfig.add(entry.data.i32[i + 1]); // height
+ highSpeedConfig.add(entry.data.i32[i + 2]); // fps_min
+ highSpeedConfig.add(entry.data.i32[i + 3]); // fps_max
+ highSpeedConfig.add(1); // batchSize_max. default to 1 for HAL3.2
+ }
+ chars.update(ANDROID_CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS,
+ highSpeedConfig);
+ }
+ }
+
+ // Keys added in HAL3.4
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
+ // Check if HAL supports RAW_OPAQUE output
+ camera_metadata_entry entry = chars.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ bool supportRawOpaque = false;
+ bool supportAnyRaw = false;
+ const int STREAM_CONFIGURATION_SIZE = 4;
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_IS_INPUT_OFFSET = 3;
+ Vector<int32_t> rawOpaqueSizes;
+
+ for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+ int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+ supportRawOpaque = true;
+ rawOpaqueSizes.push(width);
+ rawOpaqueSizes.push(height);
+ // 2 bytes per pixel. This rough estimation is only used when
+ // HAL does not fill in the opaque raw size
+ rawOpaqueSizes.push(width * height *2);
+ }
+ if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ (format == HAL_PIXEL_FORMAT_RAW16 ||
+ format == HAL_PIXEL_FORMAT_RAW10 ||
+ format == HAL_PIXEL_FORMAT_RAW12 ||
+ format == HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
+ supportAnyRaw = true;
+ }
+ }
+
+ if (supportRawOpaque) {
+ entry = chars.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+ if (entry.count == 0) {
+ // Fill in estimated value if HAL does not list it
+ chars.update(ANDROID_SENSOR_OPAQUE_RAW_SIZE, rawOpaqueSizes);
+ derivedCharKeys.push(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+ }
+ }
+
+ // Check if HAL supports any RAW output, if so, fill in postRawSensitivityBoost range
+ if (supportAnyRaw) {
+ int32_t defaultRange[2] = {100, 100};
+ entry = chars.find(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+ if (entry.count == 0) {
+ // Fill in default value (100, 100)
+ chars.update(
+ ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE,
+ defaultRange, 2);
+ derivedCharKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE);
+ // Actual request/results will be derived by camera device.
+ derivedRequestKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST);
+ derivedResultKeys.push(ANDROID_CONTROL_POST_RAW_SENSITIVITY_BOOST);
+ }
+ }
+ }
+
+ // Always add a default for the pre-correction active array if the vendor chooses to omit this
+ camera_metadata_entry entry = chars.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ if (entry.count == 0) {
+ Vector<int32_t> preCorrectionArray;
+ entry = chars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+ preCorrectionArray.appendArray(entry.data.i32, entry.count);
+ chars.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, preCorrectionArray);
+ derivedCharKeys.push(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ }
+
+ // Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS
+ // This has to be done at this end of this function.
+ if (derivedCharKeys.size() > 0) {
+ appendAvailableKeys(
+ chars, ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, derivedCharKeys);
+ }
+ if (derivedRequestKeys.size() > 0) {
+ appendAvailableKeys(
+ chars, ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, derivedRequestKeys);
+ }
+ if (derivedResultKeys.size() > 0) {
+ appendAvailableKeys(
+ chars, ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, derivedResultKeys);
+ }
+ return;
+}
+
+void CameraModule::appendAvailableKeys(CameraMetadata &chars,
+ int32_t keyTag, const Vector<int32_t>& appendKeys) {
+ camera_metadata_entry entry = chars.find(keyTag);
+ Vector<int32_t> availableKeys;
+ availableKeys.setCapacity(entry.count + appendKeys.size());
+ for (size_t i = 0; i < entry.count; i++) {
+ availableKeys.push(entry.data.i32[i]);
+ }
+ for (size_t i = 0; i < appendKeys.size(); i++) {
+ availableKeys.push(appendKeys[i]);
+ }
+ chars.update(keyTag, availableKeys);
+}
+
+CameraModule::CameraModule(camera_module_t *module) {
+ if (module == NULL) {
+ ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
+ assert(0);
+ }
+ mModule = module;
+}
+
+CameraModule::~CameraModule()
+{
+ while (mCameraInfoMap.size() > 0) {
+ camera_info cameraInfo = mCameraInfoMap.editValueAt(0);
+ if (cameraInfo.static_camera_characteristics != NULL) {
+ free_camera_metadata(
+ const_cast<camera_metadata_t*>(cameraInfo.static_camera_characteristics));
+ }
+ mCameraInfoMap.removeItemsAt(0);
+ }
+}
+
+int CameraModule::init() {
+ ATRACE_CALL();
+ int res = OK;
+ if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4 &&
+ mModule->init != NULL) {
+ ATRACE_BEGIN("camera_module->init");
+ res = mModule->init();
+ ATRACE_END();
+ }
+ mCameraInfoMap.setCapacity(getNumberOfCameras());
+ return res;
+}
+
+int CameraModule::getCameraInfo(int cameraId, struct camera_info *info) {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mCameraInfoLock);
+ if (cameraId < 0) {
+ ALOGE("%s: Invalid camera ID %d", __FUNCTION__, cameraId);
+ return -EINVAL;
+ }
+
+ // Only override static_camera_characteristics for API2 devices
+ int apiVersion = mModule->common.module_api_version;
+ if (apiVersion < CAMERA_MODULE_API_VERSION_2_0) {
+ int ret;
+ ATRACE_BEGIN("camera_module->get_camera_info");
+ ret = mModule->get_camera_info(cameraId, info);
+ // Fill in this so CameraService won't be confused by
+ // possibly 0 device_version
+ info->device_version = CAMERA_DEVICE_API_VERSION_1_0;
+ ATRACE_END();
+ return ret;
+ }
+
+ ssize_t index = mCameraInfoMap.indexOfKey(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ // Get camera info from raw module and cache it
+ camera_info rawInfo, cameraInfo;
+ ATRACE_BEGIN("camera_module->get_camera_info");
+ int ret = mModule->get_camera_info(cameraId, &rawInfo);
+ ATRACE_END();
+ if (ret != 0) {
+ return ret;
+ }
+ int deviceVersion = rawInfo.device_version;
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_0) {
+ // static_camera_characteristics is invalid
+ *info = rawInfo;
+ return ret;
+ }
+ CameraMetadata m;
+ m = rawInfo.static_camera_characteristics;
+ deriveCameraCharacteristicsKeys(rawInfo.device_version, m);
+ cameraInfo = rawInfo;
+ cameraInfo.static_camera_characteristics = m.release();
+ index = mCameraInfoMap.add(cameraId, cameraInfo);
+ }
+
+ assert(index != NAME_NOT_FOUND);
+ // return the cached camera info
+ *info = mCameraInfoMap[index];
+ return OK;
+}
+
+int CameraModule::getDeviceVersion(int cameraId) {
+ ssize_t index = mDeviceVersionMap.indexOfKey(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ int deviceVersion;
+ if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) {
+ struct camera_info info;
+ getCameraInfo(cameraId, &info);
+ deviceVersion = info.device_version;
+ } else {
+ deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+ }
+ index = mDeviceVersionMap.add(cameraId, deviceVersion);
+ }
+ assert(index != NAME_NOT_FOUND);
+ return mDeviceVersionMap[index];
+}
+
+int CameraModule::open(const char* id, struct hw_device_t** device) {
+ int res;
+ ATRACE_BEGIN("camera_module->open");
+ res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
+ ATRACE_END();
+ return res;
+}
+
+bool CameraModule::isOpenLegacyDefined() const {
+ if (getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_3) {
+ return false;
+ }
+ return mModule->open_legacy != NULL;
+}
+
+int CameraModule::openLegacy(
+ const char* id, uint32_t halVersion, struct hw_device_t** device) {
+ int res;
+ ATRACE_BEGIN("camera_module->open_legacy");
+ res = mModule->open_legacy(&mModule->common, id, halVersion, device);
+ ATRACE_END();
+ return res;
+}
+
+int CameraModule::getNumberOfCameras() {
+ int numCameras;
+ ATRACE_BEGIN("camera_module->get_number_of_cameras");
+ numCameras = mModule->get_number_of_cameras();
+ ATRACE_END();
+ return numCameras;
+}
+
+int CameraModule::setCallbacks(const camera_module_callbacks_t *callbacks) {
+ int res;
+ ATRACE_BEGIN("camera_module->set_callbacks");
+ res = mModule->set_callbacks(callbacks);
+ ATRACE_END();
+ return res;
+}
+
+bool CameraModule::isVendorTagDefined() const {
+ return mModule->get_vendor_tag_ops != NULL;
+}
+
+void CameraModule::getVendorTagOps(vendor_tag_ops_t* ops) {
+ if (mModule->get_vendor_tag_ops) {
+ ATRACE_BEGIN("camera_module->get_vendor_tag_ops");
+ mModule->get_vendor_tag_ops(ops);
+ ATRACE_END();
+ }
+}
+
+bool CameraModule::isSetTorchModeSupported() const {
+ if (getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
+ if (mModule->set_torch_mode == NULL) {
+ ALOGE("%s: Module 2.4 device must support set torch API!",
+ __FUNCTION__);
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+int CameraModule::setTorchMode(const char* camera_id, bool enable) {
+ int res = INVALID_OPERATION;
+ if (mModule->set_torch_mode != NULL) {
+ ATRACE_BEGIN("camera_module->set_torch_mode");
+ res = mModule->set_torch_mode(camera_id, enable);
+ ATRACE_END();
+ }
+ return res;
+}
+
+status_t CameraModule::filterOpenErrorCode(status_t err) {
+ switch(err) {
+ case NO_ERROR:
+ case -EBUSY:
+ case -EINVAL:
+ case -EUSERS:
+ return err;
+ default:
+ break;
+ }
+ return -ENODEV;
+}
+
+uint16_t CameraModule::getModuleApiVersion() const {
+ return mModule->common.module_api_version;
+}
+
+const char* CameraModule::getModuleName() const {
+ return mModule->common.name;
+}
+
+uint16_t CameraModule::getHalApiVersion() const {
+ return mModule->common.hal_api_version;
+}
+
+const char* CameraModule::getModuleAuthor() const {
+ return mModule->common.author;
+}
+
+void* CameraModule::getDso() {
+ return mModule->common.dso;
+}
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/VendorTagDescriptor.cpp b/camera/common/1.0/default/VendorTagDescriptor.cpp
new file mode 100644
index 0000000..db884a8
--- /dev/null
+++ b/camera/common/1.0/default/VendorTagDescriptor.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamComm1.0-VTDesc"
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <system/camera_metadata.h>
+#include <camera_metadata_hidden.h>
+
+#include "VendorTagDescriptor.h"
+
+#include <stdio.h>
+#include <string.h>
+
+namespace android {
+namespace hardware {
+namespace camera2 {
+namespace params {
+
+VendorTagDescriptor::~VendorTagDescriptor() {
+ size_t len = mReverseMapping.size();
+ for (size_t i = 0; i < len; ++i) {
+ delete mReverseMapping[i];
+ }
+}
+
+VendorTagDescriptor::VendorTagDescriptor() :
+ mTagCount(0),
+ mVendorOps() {
+}
+
+VendorTagDescriptor::VendorTagDescriptor(const VendorTagDescriptor& src) {
+ copyFrom(src);
+}
+
+VendorTagDescriptor& VendorTagDescriptor::operator=(const VendorTagDescriptor& rhs) {
+ copyFrom(rhs);
+ return *this;
+}
+
+void VendorTagDescriptor::copyFrom(const VendorTagDescriptor& src) {
+ if (this == &src) return;
+
+ size_t len = mReverseMapping.size();
+ for (size_t i = 0; i < len; ++i) {
+ delete mReverseMapping[i];
+ }
+ mReverseMapping.clear();
+
+ len = src.mReverseMapping.size();
+ // Have to copy KeyedVectors inside mReverseMapping
+ for (size_t i = 0; i < len; ++i) {
+ KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+ *nameMapper = *(src.mReverseMapping.valueAt(i));
+ mReverseMapping.add(src.mReverseMapping.keyAt(i), nameMapper);
+ }
+ // Everything else is simple
+ mTagToNameMap = src.mTagToNameMap;
+ mTagToSectionMap = src.mTagToSectionMap;
+ mTagToTypeMap = src.mTagToTypeMap;
+ mSections = src.mSections;
+ mTagCount = src.mTagCount;
+ mVendorOps = src.mVendorOps;
+}
+
+int VendorTagDescriptor::getTagCount() const {
+ size_t size = mTagToNameMap.size();
+ if (size == 0) {
+ return VENDOR_TAG_COUNT_ERR;
+ }
+ return size;
+}
+
+void VendorTagDescriptor::getTagArray(uint32_t* tagArray) const {
+ size_t size = mTagToNameMap.size();
+ for (size_t i = 0; i < size; ++i) {
+ tagArray[i] = mTagToNameMap.keyAt(i);
+ }
+}
+
+const char* VendorTagDescriptor::getSectionName(uint32_t tag) const {
+ ssize_t index = mTagToSectionMap.indexOfKey(tag);
+ if (index < 0) {
+ return VENDOR_SECTION_NAME_ERR;
+ }
+ return mSections[mTagToSectionMap.valueAt(index)].string();
+}
+
+ssize_t VendorTagDescriptor::getSectionIndex(uint32_t tag) const {
+ return mTagToSectionMap.valueFor(tag);
+}
+
+const char* VendorTagDescriptor::getTagName(uint32_t tag) const {
+ ssize_t index = mTagToNameMap.indexOfKey(tag);
+ if (index < 0) {
+ return VENDOR_TAG_NAME_ERR;
+ }
+ return mTagToNameMap.valueAt(index).string();
+}
+
+int VendorTagDescriptor::getTagType(uint32_t tag) const {
+ ssize_t index = mTagToNameMap.indexOfKey(tag);
+ if (index < 0) {
+ return VENDOR_TAG_TYPE_ERR;
+ }
+ return mTagToTypeMap.valueFor(tag);
+}
+
+const SortedVector<String8>* VendorTagDescriptor::getAllSectionNames() const {
+ return &mSections;
+}
+
+status_t VendorTagDescriptor::lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const {
+ ssize_t index = mReverseMapping.indexOfKey(section);
+ if (index < 0) {
+ ALOGE("%s: Section '%s' does not exist.", __FUNCTION__, section.string());
+ return BAD_VALUE;
+ }
+
+ ssize_t nameIndex = mReverseMapping[index]->indexOfKey(name);
+ if (nameIndex < 0) {
+ ALOGE("%s: Tag name '%s' does not exist.", __FUNCTION__, name.string());
+ return BAD_VALUE;
+ }
+
+ if (tag != NULL) {
+ *tag = mReverseMapping[index]->valueAt(nameIndex);
+ }
+ return OK;
+}
+
+void VendorTagDescriptor::dump(int fd, int verbosity, int indentation) const {
+
+ size_t size = mTagToNameMap.size();
+ if (size == 0) {
+ dprintf(fd, "%*sDumping configured vendor tag descriptors: None set\n",
+ indentation, "");
+ return;
+ }
+
+ dprintf(fd, "%*sDumping configured vendor tag descriptors: %zu entries\n",
+ indentation, "", size);
+ for (size_t i = 0; i < size; ++i) {
+ uint32_t tag = mTagToNameMap.keyAt(i);
+
+ if (verbosity < 1) {
+ dprintf(fd, "%*s0x%x\n", indentation + 2, "", tag);
+ continue;
+ }
+ String8 name = mTagToNameMap.valueAt(i);
+ uint32_t sectionId = mTagToSectionMap.valueFor(tag);
+ String8 sectionName = mSections[sectionId];
+ int type = mTagToTypeMap.valueFor(tag);
+ const char* typeName = (type >= 0 && type < NUM_TYPES) ?
+ camera_metadata_type_names[type] : "UNKNOWN";
+ dprintf(fd, "%*s0x%x (%s) with type %d (%s) defined in section %s\n", indentation + 2,
+ "", tag, name.string(), type, typeName, sectionName.string());
+ }
+
+}
+
+} // namespace params
+} // namespace camera2
+
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+extern "C" {
+
+static int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* v);
+static void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* v, uint32_t* tagArray);
+static const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* v, uint32_t tag);
+static const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* v, uint32_t tag);
+static int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* v, uint32_t tag);
+
+} /* extern "C" */
+
+static Mutex sLock;
+static sp<VendorTagDescriptor> sGlobalVendorTagDescriptor;
+
+status_t VendorTagDescriptor::createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+ /*out*/
+ sp<VendorTagDescriptor>& descriptor) {
+ if (vOps == NULL) {
+ ALOGE("%s: vendor_tag_ops argument was NULL.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ int tagCount = vOps->get_tag_count(vOps);
+ if (tagCount < 0 || tagCount > INT32_MAX) {
+ ALOGE("%s: tag count %d from vendor ops is invalid.", __FUNCTION__, tagCount);
+ return BAD_VALUE;
+ }
+
+ Vector<uint32_t> tagArray;
+ LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
+ "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+
+ vOps->get_all_tags(vOps, /*out*/tagArray.editArray());
+
+ sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+ desc->mTagCount = tagCount;
+
+ SortedVector<String8> sections;
+ KeyedVector<uint32_t, String8> tagToSectionMap;
+
+ for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+ uint32_t tag = tagArray[i];
+ if (tag < CAMERA_METADATA_VENDOR_TAG_BOUNDARY) {
+ ALOGE("%s: vendor tag %d not in vendor tag section.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+ const char *tagName = vOps->get_tag_name(vOps, tag);
+ if (tagName == NULL) {
+ ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+ desc->mTagToNameMap.add(tag, String8(tagName));
+ const char *sectionName = vOps->get_section_name(vOps, tag);
+ if (sectionName == NULL) {
+ ALOGE("%s: no section name defined for vendor tag %d.", __FUNCTION__, tag);
+ return BAD_VALUE;
+ }
+
+ String8 sectionString(sectionName);
+
+ sections.add(sectionString);
+ tagToSectionMap.add(tag, sectionString);
+
+ int tagType = vOps->get_tag_type(vOps, tag);
+ if (tagType < 0 || tagType >= NUM_TYPES) {
+ ALOGE("%s: tag type %d from vendor ops does not exist.", __FUNCTION__, tagType);
+ return BAD_VALUE;
+ }
+ desc->mTagToTypeMap.add(tag, tagType);
+ }
+
+ desc->mSections = sections;
+
+ for (size_t i = 0; i < static_cast<size_t>(tagCount); ++i) {
+ uint32_t tag = tagArray[i];
+ String8 sectionString = tagToSectionMap.valueFor(tag);
+
+ // Set up tag to section index map
+ ssize_t index = sections.indexOf(sectionString);
+ LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
+ desc->mTagToSectionMap.add(tag, static_cast<uint32_t>(index));
+
+ // Set up reverse mapping
+ ssize_t reverseIndex = -1;
+ if ((reverseIndex = desc->mReverseMapping.indexOfKey(sectionString)) < 0) {
+ KeyedVector<String8, uint32_t>* nameMapper = new KeyedVector<String8, uint32_t>();
+ reverseIndex = desc->mReverseMapping.add(sectionString, nameMapper);
+ }
+ desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
+ }
+
+ descriptor = desc;
+ return OK;
+}
+
+status_t VendorTagDescriptor::setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc) {
+ status_t res = OK;
+ Mutex::Autolock al(sLock);
+ sGlobalVendorTagDescriptor = desc;
+
+ vendor_tag_ops_t* opsPtr = NULL;
+ if (desc != NULL) {
+ opsPtr = &(desc->mVendorOps);
+ opsPtr->get_tag_count = vendor_tag_descriptor_get_tag_count;
+ opsPtr->get_all_tags = vendor_tag_descriptor_get_all_tags;
+ opsPtr->get_section_name = vendor_tag_descriptor_get_section_name;
+ opsPtr->get_tag_name = vendor_tag_descriptor_get_tag_name;
+ opsPtr->get_tag_type = vendor_tag_descriptor_get_tag_type;
+ }
+ if((res = set_camera_metadata_vendor_ops(opsPtr)) != OK) {
+ ALOGE("%s: Could not set vendor tag descriptor, received error %s (%d)."
+ , __FUNCTION__, strerror(-res), res);
+ }
+ return res;
+}
+
+void VendorTagDescriptor::clearGlobalVendorTagDescriptor() {
+ Mutex::Autolock al(sLock);
+ set_camera_metadata_vendor_ops(NULL);
+ sGlobalVendorTagDescriptor.clear();
+}
+
+sp<VendorTagDescriptor> VendorTagDescriptor::getGlobalVendorTagDescriptor() {
+ Mutex::Autolock al(sLock);
+ return sGlobalVendorTagDescriptor;
+}
+
+extern "C" {
+
+int vendor_tag_descriptor_get_tag_count(const vendor_tag_ops_t* /*v*/) {
+ Mutex::Autolock al(sLock);
+ if (sGlobalVendorTagDescriptor == NULL) {
+ ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+ return VENDOR_TAG_COUNT_ERR;
+ }
+ return sGlobalVendorTagDescriptor->getTagCount();
+}
+
+void vendor_tag_descriptor_get_all_tags(const vendor_tag_ops_t* /*v*/, uint32_t* tagArray) {
+ Mutex::Autolock al(sLock);
+ if (sGlobalVendorTagDescriptor == NULL) {
+ ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+ return;
+ }
+ sGlobalVendorTagDescriptor->getTagArray(tagArray);
+}
+
+const char* vendor_tag_descriptor_get_section_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+ Mutex::Autolock al(sLock);
+ if (sGlobalVendorTagDescriptor == NULL) {
+ ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+ return VENDOR_SECTION_NAME_ERR;
+ }
+ return sGlobalVendorTagDescriptor->getSectionName(tag);
+}
+
+const char* vendor_tag_descriptor_get_tag_name(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+ Mutex::Autolock al(sLock);
+ if (sGlobalVendorTagDescriptor == NULL) {
+ ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+ return VENDOR_TAG_NAME_ERR;
+ }
+ return sGlobalVendorTagDescriptor->getTagName(tag);
+}
+
+int vendor_tag_descriptor_get_tag_type(const vendor_tag_ops_t* /*v*/, uint32_t tag) {
+ Mutex::Autolock al(sLock);
+ if (sGlobalVendorTagDescriptor == NULL) {
+ ALOGE("%s: Vendor tag descriptor not initialized.", __FUNCTION__);
+ return VENDOR_TAG_TYPE_ERR;
+ }
+ return sGlobalVendorTagDescriptor->getTagType(tag);
+}
+
+} /* extern "C" */
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/common/1.0/default/include/CameraMetadata.h b/camera/common/1.0/default/include/CameraMetadata.h
new file mode 100644
index 0000000..d5e4d56
--- /dev/null
+++ b/camera/common/1.0/default/include/CameraMetadata.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAMERA_COMMON_1_0_CAMERAMETADATA_H
+#define CAMERA_COMMON_1_0_CAMERAMETADATA_H
+
+#include "system/camera_metadata.h"
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+class VendorTagDescriptor;
+
+/**
+ * A convenience wrapper around the C-based camera_metadata_t library.
+ */
+class CameraMetadata {
+ public:
+ /** Creates an empty object; best used when expecting to acquire contents
+ * from elsewhere */
+ CameraMetadata();
+ /** Creates an object with space for entryCapacity entries, with
+ * dataCapacity extra storage */
+ CameraMetadata(size_t entryCapacity, size_t dataCapacity = 10);
+
+ ~CameraMetadata();
+
+ /** Takes ownership of passed-in buffer */
+ CameraMetadata(camera_metadata_t *buffer);
+ /** Clones the metadata */
+ CameraMetadata(const CameraMetadata &other);
+
+ /**
+ * Assignment clones metadata buffer.
+ */
+ CameraMetadata &operator=(const CameraMetadata &other);
+ CameraMetadata &operator=(const camera_metadata_t *buffer);
+
+ /**
+ * Get reference to the underlying metadata buffer. Ownership remains with
+ * the CameraMetadata object, but non-const CameraMetadata methods will not
+ * work until unlock() is called. Note that the lock has nothing to do with
+ * thread-safety, it simply prevents the camera_metadata_t pointer returned
+ * here from being accidentally invalidated by CameraMetadata operations.
+ */
+ const camera_metadata_t* getAndLock() const;
+
+ /**
+ * Unlock the CameraMetadata for use again. After this unlock, the pointer
+ * given from getAndLock() may no longer be used. The pointer passed out
+ * from getAndLock must be provided to guarantee that the right object is
+ * being unlocked.
+ */
+ status_t unlock(const camera_metadata_t *buffer) const;
+
+ /**
+ * Release a raw metadata buffer to the caller. After this call,
+ * CameraMetadata no longer references the buffer, and the caller takes
+ * responsibility for freeing the raw metadata buffer (using
+ * free_camera_metadata()), or for handing it to another CameraMetadata
+ * instance.
+ */
+ camera_metadata_t* release();
+
+ /**
+ * Clear the metadata buffer and free all storage used by it
+ */
+ void clear();
+
+ /**
+ * Acquire a raw metadata buffer from the caller. After this call,
+ * the caller no longer owns the raw buffer, and must not free or manipulate it.
+ * If CameraMetadata already contains metadata, it is freed.
+ */
+ void acquire(camera_metadata_t* buffer);
+
+ /**
+ * Acquires raw buffer from other CameraMetadata object. After the call, the argument
+ * object no longer has any metadata.
+ */
+ void acquire(CameraMetadata &other);
+
+ /**
+ * Append metadata from another CameraMetadata object.
+ */
+ status_t append(const CameraMetadata &other);
+
+ /**
+ * Append metadata from a raw camera_metadata buffer
+ */
+ status_t append(const camera_metadata* other);
+
+ /**
+ * Number of metadata entries.
+ */
+ size_t entryCount() const;
+
+ /**
+ * Is the buffer empty (no entires)
+ */
+ bool isEmpty() const;
+
+ /**
+ * Sort metadata buffer for faster find
+ */
+ status_t sort();
+
+ /**
+ * Update metadata entry. Will create entry if it doesn't exist already, and
+ * will reallocate the buffer if insufficient space exists. Overloaded for
+ * the various types of valid data.
+ */
+ status_t update(uint32_t tag,
+ const uint8_t *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const int32_t *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const float *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const int64_t *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const double *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const camera_metadata_rational_t *data, size_t data_count);
+ status_t update(uint32_t tag,
+ const String8 &string);
+ status_t update(const camera_metadata_ro_entry &entry);
+
+
+ template<typename T>
+ status_t update(uint32_t tag, Vector<T> data) {
+ return update(tag, data.array(), data.size());
+ }
+
+ /**
+ * Check if a metadata entry exists for a given tag id
+ *
+ */
+ bool exists(uint32_t tag) const;
+
+ /**
+ * Get metadata entry by tag id
+ */
+ camera_metadata_entry find(uint32_t tag);
+
+ /**
+ * Get metadata entry by tag id, with no editing
+ */
+ camera_metadata_ro_entry find(uint32_t tag) const;
+
+ /**
+ * Delete metadata entry by tag
+ */
+ status_t erase(uint32_t tag);
+
+ /**
+ * Swap the underlying camera metadata between this and the other
+ * metadata object.
+ */
+ void swap(CameraMetadata &other);
+
+ /**
+ * Dump contents into FD for debugging. The verbosity levels are
+ * 0: Tag entry information only, no data values
+ * 1: Level 0 plus at most 16 data values per entry
+ * 2: All information
+ *
+ * The indentation parameter sets the number of spaces to add to the start
+ * each line of output.
+ */
+ void dump(int fd, int verbosity = 1, int indentation = 0) const;
+
+ /**
+ * Find tag id for a given tag name, also checking vendor tags if available.
+ * On success, returns OK and writes the tag id into tag.
+ *
+ * This is a slow method.
+ */
+ static status_t getTagFromName(const char *name,
+ const VendorTagDescriptor* vTags, uint32_t *tag);
+
+ private:
+ camera_metadata_t *mBuffer;
+ mutable bool mLocked;
+
+ /**
+ * Check if tag has a given type
+ */
+ status_t checkType(uint32_t tag, uint8_t expectedType);
+
+ /**
+ * Base update entry method
+ */
+ status_t updateImpl(uint32_t tag, const void *data, size_t data_count);
+
+ /**
+ * Resize metadata buffer if needed by reallocating it and copying it over.
+ */
+ status_t resizeIfNeeded(size_t extraEntries, size_t extraData);
+
+};
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif
diff --git a/camera/common/1.0/default/include/CameraModule.h b/camera/common/1.0/default/include/CameraModule.h
new file mode 100644
index 0000000..68d4f90
--- /dev/null
+++ b/camera/common/1.0/default/include/CameraModule.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAMERA_COMMON_1_0_CAMERAMODULE_H
+#define CAMERA_COMMON_1_0_CAMERAMODULE_H
+
+#include <hardware/camera.h>
+#include <utils/Mutex.h>
+#include <utils/KeyedVector.h>
+
+#include "CameraMetadata.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+/**
+ * A wrapper class for HAL camera module.
+ *
+ * This class wraps camera_module_t returned from HAL to provide a wrapped
+ * get_camera_info implementation which CameraService generates some
+ * camera characteristics keys defined in newer HAL version on an older HAL.
+ */
+class CameraModule : public RefBase {
+public:
+ explicit CameraModule(camera_module_t *module);
+ virtual ~CameraModule();
+
+ // Must be called after construction
+ // Returns OK on success, NO_INIT on failure
+ int init();
+
+ int getCameraInfo(int cameraId, struct camera_info *info);
+ int getDeviceVersion(int cameraId);
+ int getNumberOfCameras(void);
+ int open(const char* id, struct hw_device_t** device);
+ bool isOpenLegacyDefined() const;
+ int openLegacy(const char* id, uint32_t halVersion, struct hw_device_t** device);
+ int setCallbacks(const camera_module_callbacks_t *callbacks);
+ bool isVendorTagDefined() const;
+ void getVendorTagOps(vendor_tag_ops_t* ops);
+ bool isSetTorchModeSupported() const;
+ int setTorchMode(const char* camera_id, bool enable);
+ uint16_t getModuleApiVersion() const;
+ const char* getModuleName() const;
+ uint16_t getHalApiVersion() const;
+ const char* getModuleAuthor() const;
+ // Only used by CameraModuleFixture native test. Do NOT use elsewhere.
+ void *getDso();
+
+private:
+ // Derive camera characteristics keys defined after HAL device version
+ static void deriveCameraCharacteristicsKeys(uint32_t deviceVersion, CameraMetadata &chars);
+ // Helper function to append available[request|result|chars]Keys
+ static void appendAvailableKeys(CameraMetadata &chars,
+ int32_t keyTag, const Vector<int32_t>& appendKeys);
+ status_t filterOpenErrorCode(status_t err);
+ camera_module_t *mModule;
+ KeyedVector<int, camera_info> mCameraInfoMap;
+ KeyedVector<int, int> mDeviceVersionMap;
+ Mutex mCameraInfoLock;
+};
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif
diff --git a/camera/common/1.0/default/include/VendorTagDescriptor.h b/camera/common/1.0/default/include/VendorTagDescriptor.h
new file mode 100644
index 0000000..8d8ded9
--- /dev/null
+++ b/camera/common/1.0/default/include/VendorTagDescriptor.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
+#define CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H
+
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/RefBase.h>
+#include <system/camera_vendor_tags.h>
+
+#include <stdint.h>
+
+namespace android {
+namespace hardware {
+namespace camera2 {
+namespace params {
+
+/**
+ * VendorTagDescriptor objects are containers for the vendor tag
+ * definitions provided, and are typically used to pass the vendor tag
+ * information enumerated by the HAL to clients of the camera service.
+ */
+class VendorTagDescriptor {
+ public:
+ virtual ~VendorTagDescriptor();
+
+ VendorTagDescriptor();
+ VendorTagDescriptor(const VendorTagDescriptor& src);
+ VendorTagDescriptor& operator=(const VendorTagDescriptor& rhs);
+
+ void copyFrom(const VendorTagDescriptor& src);
+
+ /**
+ * The following 'get*' methods implement the corresponding
+ * functions defined in
+ * system/media/camera/include/system/camera_vendor_tags.h
+ */
+
+ // Returns the number of vendor tags defined.
+ int getTagCount() const;
+
+ // Returns an array containing the id's of vendor tags defined.
+ void getTagArray(uint32_t* tagArray) const;
+
+ // Returns the section name string for a given vendor tag id.
+ const char* getSectionName(uint32_t tag) const;
+
+ // Returns the index in section vectors returned in getAllSectionNames()
+ // for a given vendor tag id. -1 if input tag does not exist.
+ ssize_t getSectionIndex(uint32_t tag) const;
+
+ // Returns the tag name string for a given vendor tag id.
+ const char* getTagName(uint32_t tag) const;
+
+ // Returns the tag type for a given vendor tag id.
+ int getTagType(uint32_t tag) const;
+
+ /**
+ * Convenience method to get a vector containing all vendor tag
+ * sections, or an empty vector if none are defined.
+ * The pointer is valid for the lifetime of the VendorTagDescriptor,
+ * or until copyFrom is invoked.
+ */
+ const SortedVector<String8>* getAllSectionNames() const;
+
+ /**
+ * Lookup the tag id for a given tag name and section.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ status_t lookupTag(const String8& name, const String8& section, /*out*/uint32_t* tag) const;
+
+ /**
+ * Dump the currently configured vendor tags to a file descriptor.
+ */
+ void dump(int fd, int verbosity, int indentation) const;
+
+ protected:
+ KeyedVector<String8, KeyedVector<String8, uint32_t>*> mReverseMapping;
+ KeyedVector<uint32_t, String8> mTagToNameMap;
+ KeyedVector<uint32_t, uint32_t> mTagToSectionMap; // Value is offset in mSections
+ KeyedVector<uint32_t, int32_t> mTagToTypeMap;
+ SortedVector<String8> mSections;
+ // must be int32_t to be compatible with Parcel::writeInt32
+ int32_t mTagCount;
+
+ vendor_tag_ops mVendorOps;
+};
+} /* namespace params */
+} /* namespace camera2 */
+
+namespace camera {
+namespace common {
+namespace V1_0 {
+namespace helper {
+
+/**
+ * This version of VendorTagDescriptor must be stored in Android sp<>, and adds support for using it
+ * as a global tag descriptor.
+ *
+ * It's a child class of the basic hardware::camera2::params::VendorTagDescriptor since basic
+ * Parcelable objects cannot require being kept in an sp<> and still work with auto-generated AIDL
+ * interface implementations.
+ */
+class VendorTagDescriptor :
+ public ::android::hardware::camera2::params::VendorTagDescriptor,
+ public LightRefBase<VendorTagDescriptor> {
+
+ public:
+
+ /**
+ * Create a VendorTagDescriptor object from the given vendor_tag_ops_t
+ * struct.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ static status_t createDescriptorFromOps(const vendor_tag_ops_t* vOps,
+ /*out*/
+ sp<VendorTagDescriptor>& descriptor);
+
+ /**
+ * Sets the global vendor tag descriptor to use for this process.
+ * Camera metadata operations that access vendor tags will use the
+ * vendor tag definitions set this way.
+ *
+ * Returns OK on success, or a negative error code.
+ */
+ static status_t setAsGlobalVendorTagDescriptor(const sp<VendorTagDescriptor>& desc);
+
+ /**
+ * Returns the global vendor tag descriptor used by this process.
+ * This will contain NULL if no vendor tags are defined.
+ */
+ static sp<VendorTagDescriptor> getGlobalVendorTagDescriptor();
+
+ /**
+ * Clears the global vendor tag descriptor used by this process.
+ */
+ static void clearGlobalVendorTagDescriptor();
+
+};
+
+} // namespace helper
+} // namespace V1_0
+} // namespace common
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif /* CAMERA_COMMON_1_0_VENDORTAGDESCRIPTOR_H */
diff --git a/camera/device/3.2/ICameraDeviceSession.hal b/camera/device/3.2/ICameraDeviceSession.hal
index c8cc246..e92d756 100644
--- a/camera/device/3.2/ICameraDeviceSession.hal
+++ b/camera/device/3.2/ICameraDeviceSession.hal
@@ -48,6 +48,8 @@
* INTERNAL_ERROR:
* An unexpected internal error occurred, and the default settings
* are not available.
+ * ILLEGAL_ARGUMENT:
+ * The camera HAL does not support the input template type
* CAMERA_DISCONNECTED:
* An external camera device has been disconnected, and is no longer
* available. This camera device interface is now stale, and a new
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
new file mode 100644
index 0000000..9820220
--- /dev/null
+++ b/camera/device/3.2/default/Android.bp
@@ -0,0 +1,22 @@
+cc_library_shared {
+ name: "android.hardware.camera.device@3.2-impl",
+ srcs: ["CameraDevice.cpp",
+ "CameraDeviceSession.cpp",
+ "convert.cpp"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "libcutils",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.provider@2.4",
+ "liblog",
+ "libhardware",
+ "libcamera_metadata"
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper"
+ ],
+ export_include_dirs: ["."]
+}
diff --git a/camera/device/3.2/default/CameraDevice.cpp b/camera/device/3.2/default/CameraDevice.cpp
new file mode 100644
index 0000000..18e0e7b
--- /dev/null
+++ b/camera/device/3.2/default/CameraDevice.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamDev@3.2-impl"
+#include <android/log.h>
+
+#include <utils/Vector.h>
+#include <utils/Trace.h>
+#include "CameraDevice.h"
+#include <include/convert.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::camera::common::V1_0::Status;
+
+CameraDevice::CameraDevice(
+ sp<CameraModule> module, const std::string& cameraId,
+ const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) :
+ mModule(module),
+ mCameraId(cameraId),
+ mDisconnected(false),
+ mCameraDeviceNames(cameraDeviceNames) {
+ mCameraIdInt = atoi(mCameraId.c_str());
+ // Should not reach here as provider also validate ID
+ if (mCameraIdInt < 0 || mCameraIdInt >= module->getNumberOfCameras()) {
+ ALOGE("%s: Invalid camera id: %s", __FUNCTION__, mCameraId.c_str());
+ mInitFail = true;
+ }
+
+ mDeviceVersion = mModule->getDeviceVersion(mCameraIdInt);
+ if (mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+ ALOGE("%s: Camera id %s does not support HAL3.2+",
+ __FUNCTION__, mCameraId.c_str());
+ mInitFail = true;
+ }
+}
+
+CameraDevice::~CameraDevice() {}
+
+Status CameraDevice::initStatus() const {
+ Mutex::Autolock _l(mLock);
+ Status status = Status::OK;
+ if (mInitFail) {
+ status = Status::INTERNAL_ERROR;
+ } else if (mDisconnected) {
+ status = Status::CAMERA_DISCONNECTED;
+ }
+ return status;
+}
+
+void CameraDevice::setConnectionStatus(bool connected) {
+ Mutex::Autolock _l(mLock);
+ mDisconnected = !connected;
+ if (mSession == nullptr) {
+ return;
+ }
+ sp<CameraDeviceSession> session = mSession.promote();
+ if (session == nullptr) {
+ return;
+ }
+ // Only notify active session disconnect events.
+ // Users will need to re-open camera after disconnect event
+ if (!connected) {
+ session->disconnect();
+ }
+ return;
+}
+
+Status CameraDevice::getHidlStatus(int status) {
+ switch (status) {
+ case 0: return Status::OK;
+ case -ENOSYS: return Status::OPERATION_NOT_SUPPORTED;
+ case -EBUSY : return Status::CAMERA_IN_USE;
+ case -EUSERS: return Status::MAX_CAMERAS_IN_USE;
+ case -ENODEV: return Status::INTERNAL_ERROR;
+ case -EINVAL: return Status::ILLEGAL_ARGUMENT;
+ default:
+ ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status);
+ return Status::INTERNAL_ERROR;
+ }
+}
+
+// Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow.
+Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb) {
+ Status status = initStatus();
+ CameraResourceCost resCost;
+ if (status == Status::OK) {
+ int cost = 100;
+ std::vector<std::string> conflicting_devices;
+ struct camera_info info;
+
+ // If using post-2.4 module version, query the cost + conflicting devices from the HAL
+ if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
+ int ret = mModule->getCameraInfo(mCameraIdInt, &info);
+ if (ret == OK) {
+ cost = info.resource_cost;
+ for (size_t i = 0; i < info.conflicting_devices_length; i++) {
+ std::string cameraId(info.conflicting_devices[i]);
+ for (const auto& pair : mCameraDeviceNames) {
+ if (cameraId == pair.first) {
+ conflicting_devices.push_back(pair.second);
+ }
+ }
+ }
+ } else {
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+
+ if (status == Status::OK) {
+ resCost.resourceCost = cost;
+ resCost.conflictingDevices.resize(conflicting_devices.size());
+ for (size_t i = 0; i < conflicting_devices.size(); i++) {
+ resCost.conflictingDevices[i] = conflicting_devices[i];
+ ALOGV("CamDevice %s is conflicting with camDevice %s",
+ mCameraId.c_str(), resCost.conflictingDevices[i].c_str());
+ }
+ }
+ }
+ _hidl_cb(status, resCost);
+ return Void();
+}
+
+Return<void> CameraDevice::getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) {
+ Status status = initStatus();
+ CameraMetadata cameraCharacteristics;
+ if (status == Status::OK) {
+ //Module 2.1+ codepath.
+ struct camera_info info;
+ int ret = mModule->getCameraInfo(mCameraIdInt, &info);
+ if (ret == OK) {
+ convertToHidl(info.static_camera_characteristics, &cameraCharacteristics);
+ } else {
+ ALOGE("%s: get camera info failed!", __FUNCTION__);
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+ _hidl_cb(status, cameraCharacteristics);
+ return Void();
+}
+
+Return<Status> CameraDevice::setTorchMode(TorchMode mode) {
+ if (!mModule->isSetTorchModeSupported()) {
+ return Status::METHOD_NOT_SUPPORTED;
+ }
+
+ Status status = initStatus();
+ if (status == Status::OK) {
+ bool enable = (mode == TorchMode::ON) ? true : false;
+ status = getHidlStatus(mModule->setTorchMode(mCameraId.c_str(), enable));
+ }
+ return status;
+}
+
+Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) {
+ Status status = initStatus();
+ sp<CameraDeviceSession> session = nullptr;
+
+ if (callback == nullptr) {
+ ALOGE("%s: cannot open camera %s. callback is null!",
+ __FUNCTION__, mCameraId.c_str());
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, session);
+ return Void();
+ }
+
+ if (status != Status::OK) {
+ // Provider will never pass initFailed device to client, so
+ // this must be a disconnected camera
+ ALOGE("%s: cannot open camera %s. camera is disconnected!",
+ __FUNCTION__, mCameraId.c_str());
+ _hidl_cb(Status::CAMERA_DISCONNECTED, session);
+ return Void();
+ } else {
+ mLock.lock();
+
+ ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mCameraIdInt);
+ session = mSession.promote();
+ if (session != nullptr && !session->isClosed()) {
+ ALOGE("%s: cannot open an already opened camera!", __FUNCTION__);
+ mLock.unlock();
+ _hidl_cb(Status::CAMERA_IN_USE, nullptr);
+ return Void();
+ }
+
+ /** Open HAL device */
+ status_t res;
+ camera3_device_t *device;
+
+ ATRACE_BEGIN("camera3->open");
+ res = mModule->open(mCameraId.c_str(),
+ reinterpret_cast<hw_device_t**>(&device));
+ ATRACE_END();
+
+ if (res != OK) {
+ ALOGE("%s: cannot open camera %s!", __FUNCTION__, mCameraId.c_str());
+ mLock.unlock();
+ _hidl_cb(getHidlStatus(res), nullptr);
+ return Void();
+ }
+
+ /** Cross-check device version */
+ if (device->common.version < CAMERA_DEVICE_API_VERSION_3_2) {
+ ALOGE("%s: Could not open camera: "
+ "Camera device should be at least %x, reports %x instead",
+ __FUNCTION__,
+ CAMERA_DEVICE_API_VERSION_3_2,
+ device->common.version);
+ device->common.close(&device->common);
+ mLock.unlock();
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ session = new CameraDeviceSession(device, callback);
+ if (session == nullptr) {
+ ALOGE("%s: camera device session allocation failed", __FUNCTION__);
+ mLock.unlock();
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+ if (session->isInitFailed()) {
+ ALOGE("%s: camera device session init failed", __FUNCTION__);
+ session = nullptr;
+ mLock.unlock();
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+ mSession = session;
+ mLock.unlock();
+ }
+ _hidl_cb(status, session);
+ return Void();
+}
+
+Return<void> CameraDevice::dumpState(const ::android::hardware::hidl_handle& handle) {
+ Mutex::Autolock _l(mLock);
+ if (handle.getNativeHandle() == nullptr) {
+ ALOGE("%s: handle must not be null", __FUNCTION__);
+ return Void();
+ }
+ if (handle->numFds != 1 || handle->numInts != 0) {
+ ALOGE("%s: handle must contain 1 FD and 0 integers! Got %d FDs and %d ints",
+ __FUNCTION__, handle->numFds, handle->numInts);
+ return Void();
+ }
+ int fd = handle->data[0];
+ if (mSession == nullptr) {
+ dprintf(fd, "No active camera device session instance\n");
+ return Void();
+ }
+ sp<CameraDeviceSession> session = mSession.promote();
+ if (session == nullptr) {
+ dprintf(fd, "No active camera device session instance\n");
+ return Void();
+ }
+ // Call into active session to dump states
+ session->dumpState(handle);
+ return Void();
+}
+// End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice.
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.2/default/CameraDevice.h b/camera/device/3.2/default/CameraDevice.h
new file mode 100644
index 0000000..317eea5
--- /dev/null
+++ b/camera/device/3.2/default/CameraDevice.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE_H
+
+#include "utils/Mutex.h"
+#include "CameraModule.h"
+#include "CameraMetadata.h"
+#include "CameraDeviceSession.h"
+
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::ICameraDevice;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using ::android::hardware::camera::common::V1_0::CameraResourceCost;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+/*
+ * The camera device HAL implementation is opened lazily (via the open call)
+ */
+struct CameraDevice : public ICameraDevice {
+ // Called by provider HAL. Provider HAL must ensure the uniqueness of
+ // CameraDevice object per cameraId, or there could be multiple CameraDevice
+ // trying to access the same physical camera.
+ // Also, provider will have to keep track of all CameraDevice object in
+ // order to notify CameraDevice when the underlying camera is detached
+ CameraDevice(sp<CameraModule> module,
+ const std::string& cameraId,
+ const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames);
+ ~CameraDevice();
+ // Caller must use this method to check if CameraDevice ctor failed
+ bool isInitFailed() { return mInitFail; }
+ // Used by provider HAL to signal external camera disconnected
+ void setConnectionStatus(bool connected);
+
+ /* Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. */
+ // The following method can be called without opening the actual camera device
+ Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override;
+ Return<void> getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override;
+ Return<Status> setTorchMode(TorchMode mode) override;
+
+ // Open the device HAL and also return a default capture session
+ Return<void> open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) override;
+
+
+ // Forward the dump call to the opened session, or do nothing
+ Return<void> dumpState(const ::android::hardware::hidl_handle& fd) override;
+ /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */
+
+private:
+ // Passed from provider HAL. Should not change.
+ sp<CameraModule> mModule;
+ const std::string mCameraId;
+ // const after ctor
+ int mCameraIdInt;
+ int mDeviceVersion;
+ bool mInitFail = false;
+ // Set by provider (when external camera is connected/disconnected)
+ bool mDisconnected;
+ wp<CameraDeviceSession> mSession = nullptr;
+
+ const SortedVector<std::pair<std::string, std::string>>& mCameraDeviceNames;
+
+ // gating access to mSession and mDisconnected
+ mutable Mutex mLock;
+
+ // convert conventional HAL status to HIDL Status
+ static Status getHidlStatus(int);
+
+ Status initStatus() const;
+};
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE_H
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
new file mode 100644
index 0000000..de61d83
--- /dev/null
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -0,0 +1,745 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamDevSession@3.2-impl"
+#include <android/log.h>
+
+#include <utils/Trace.h>
+#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
+#include "CameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+namespace {
+
+// Copy pasted from Hwc.cpp. Use this until gralloc mapper HAL is working
+class HandleImporter {
+public:
+ HandleImporter() : mInitialized(false) {}
+
+ bool initialize()
+ {
+ // allow only one client
+ if (mInitialized) {
+ return false;
+ }
+
+ if (!openGralloc()) {
+ return false;
+ }
+
+ mInitialized = true;
+ return true;
+ }
+
+ void cleanup()
+ {
+ if (!mInitialized) {
+ return;
+ }
+
+ closeGralloc();
+ mInitialized = false;
+ }
+
+ // In IComposer, any buffer_handle_t is owned by the caller and we need to
+ // make a clone for hwcomposer2. We also need to translate empty handle
+ // to nullptr. This function does that, in-place.
+ bool importBuffer(buffer_handle_t& handle)
+ {
+ if (!handle->numFds && !handle->numInts) {
+ handle = nullptr;
+ return true;
+ }
+
+ buffer_handle_t clone = cloneBuffer(handle);
+ if (!clone) {
+ return false;
+ }
+
+ handle = clone;
+ return true;
+ }
+
+ void freeBuffer(buffer_handle_t handle)
+ {
+ if (!handle) {
+ return;
+ }
+
+ releaseBuffer(handle);
+ }
+
+ bool importFence(const native_handle_t* handle, int& fd)
+ {
+ if (handle == nullptr || handle->numFds == 0) {
+ fd = -1;
+ } else if (handle->numFds == 1) {
+//TODO(b/34110242): make this hidl transport agnostic
+#ifdef BINDERIZED
+ fd = dup(handle->data[0]);
+#else
+ fd = handle->data[0];
+#endif
+ if (fd < 0) {
+ ALOGE("failed to dup fence fd %d", handle->data[0]);
+ return false;
+ }
+ } else {
+ ALOGE("invalid fence handle with %d file descriptors",
+ handle->numFds);
+ return false;
+ }
+
+ return true;
+ }
+
+ void closeFence(int fd)
+ {
+#ifdef BINDERIZED
+ if (fd >= 0) {
+ close(fd);
+ }
+#else
+ (void) fd;
+#endif
+ }
+
+private:
+ bool mInitialized;
+
+ // Some existing gralloc drivers do not support retaining more than once,
+ // when we are in passthrough mode.
+#ifdef BINDERIZED
+ bool openGralloc()
+ {
+ const hw_module_t* module;
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (err) {
+ ALOGE("failed to get gralloc module");
+ return false;
+ }
+
+ uint8_t major = (module->module_api_version >> 8) & 0xff;
+ if (major > 1) {
+ ALOGE("unknown gralloc module major version %d", major);
+ return false;
+ }
+
+ if (major == 1) {
+ err = gralloc1_open(module, &mDevice);
+ if (err) {
+ ALOGE("failed to open gralloc1 device");
+ return false;
+ }
+
+ mRetain = reinterpret_cast<GRALLOC1_PFN_RETAIN>(
+ mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RETAIN));
+ mRelease = reinterpret_cast<GRALLOC1_PFN_RELEASE>(
+ mDevice->getFunction(mDevice, GRALLOC1_FUNCTION_RELEASE));
+ if (!mRetain || !mRelease) {
+ ALOGE("invalid gralloc1 device");
+ gralloc1_close(mDevice);
+ return false;
+ }
+ } else {
+ mModule = reinterpret_cast<const gralloc_module_t*>(module);
+ }
+
+ return true;
+ }
+
+ void closeGralloc()
+ {
+ if (mDevice) {
+ gralloc1_close(mDevice);
+ }
+ }
+
+ buffer_handle_t cloneBuffer(buffer_handle_t handle)
+ {
+ native_handle_t* clone = native_handle_clone(handle);
+ if (!clone) {
+ ALOGE("failed to clone buffer %p", handle);
+ return nullptr;
+ }
+
+ bool err;
+ if (mDevice) {
+ err = (mRetain(mDevice, clone) != GRALLOC1_ERROR_NONE);
+ } else {
+ err = (mModule->registerBuffer(mModule, clone) != 0);
+ }
+
+ if (err) {
+ ALOGE("failed to retain/register buffer %p", clone);
+ native_handle_close(clone);
+ native_handle_delete(clone);
+ return nullptr;
+ }
+
+ return clone;
+ }
+
+ void releaseBuffer(buffer_handle_t handle)
+ {
+ if (mDevice) {
+ mRelease(mDevice, handle);
+ } else {
+ mModule->unregisterBuffer(mModule, handle);
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle_t*>(handle));
+ }
+ }
+
+ // gralloc1
+ gralloc1_device_t* mDevice;
+ GRALLOC1_PFN_RETAIN mRetain;
+ GRALLOC1_PFN_RELEASE mRelease;
+
+ // gralloc0
+ const gralloc_module_t* mModule;
+#else
+ bool openGralloc() { return true; }
+ void closeGralloc() {}
+ buffer_handle_t cloneBuffer(buffer_handle_t handle) { return handle; }
+ void releaseBuffer(buffer_handle_t) {}
+#endif
+};
+
+HandleImporter sHandleImporter;
+
+} // Anonymous namespace
+
+CameraDeviceSession::CameraDeviceSession(
+ camera3_device_t* device, const sp<ICameraDeviceCallback>& callback) :
+ camera3_callback_ops({&sProcessCaptureResult, &sNotify}),
+ mDevice(device),
+ mCallback(callback) {
+ // For now, we init sHandleImporter but do not cleanup (keep it alive until
+ // HAL process ends)
+ sHandleImporter.initialize();
+
+ mInitFail = initialize();
+}
+
+bool CameraDeviceSession::initialize() {
+ /** Initialize device with callback functions */
+ ATRACE_BEGIN("camera3->initialize");
+ status_t res = mDevice->ops->initialize(mDevice, this);
+ ATRACE_END();
+
+ if (res != OK) {
+ ALOGE("%s: Unable to initialize HAL device: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ mDevice->common.close(&mDevice->common);
+ mClosed = true;
+ return true;
+ }
+ return false;
+}
+
+CameraDeviceSession::~CameraDeviceSession() {
+ if (!isClosed()) {
+ ALOGE("CameraDeviceSession deleted before close!");
+ close();
+ }
+}
+
+bool CameraDeviceSession::isClosed() {
+ Mutex::Autolock _l(mStateLock);
+ return mClosed;
+}
+
+Status CameraDeviceSession::initStatus() const {
+ Mutex::Autolock _l(mStateLock);
+ Status status = Status::OK;
+ if (mInitFail) {
+ status = Status::INTERNAL_ERROR;
+ } else if (mDisconnected) {
+ status = Status::CAMERA_DISCONNECTED;
+ } else if (mClosed) {
+ status = Status::INTERNAL_ERROR;
+ }
+ return status;
+}
+
+void CameraDeviceSession::disconnect() {
+ Mutex::Autolock _l(mStateLock);
+ mDisconnected = true;
+ ALOGW("%s: Camera device is disconnected. Closing.", __FUNCTION__);
+ if (!mClosed) {
+ mDevice->common.close(&mDevice->common);
+ mClosed = true;
+ }
+}
+
+void CameraDeviceSession::dumpState(const native_handle_t* fd) {
+ if (!isClosed()) {
+ mDevice->ops->dump(mDevice, fd->data[0]);
+ }
+}
+
+Status CameraDeviceSession::importRequest(
+ const CaptureRequest& request,
+ hidl_vec<buffer_handle_t*>& allBufPtrs,
+ hidl_vec<int>& allFences) {
+ bool hasInputBuf = (request.inputBuffer.streamId != -1 &&
+ request.inputBuffer.buffer.getNativeHandle() != nullptr);
+ size_t numOutputBufs = request.outputBuffers.size();
+ size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
+ // Validate all I/O buffers
+ hidl_vec<buffer_handle_t> allBufs;
+ allBufs.resize(numBufs);
+ allBufPtrs.resize(numBufs);
+ allFences.resize(numBufs);
+ std::vector<int32_t> streamIds(numBufs);
+
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ allBufs[i] = request.outputBuffers[i].buffer.getNativeHandle();
+ allBufPtrs[i] = &allBufs[i];
+ streamIds[i] = request.outputBuffers[i].streamId;
+ }
+ if (hasInputBuf) {
+ allBufs[numOutputBufs] = request.inputBuffer.buffer.getNativeHandle();
+ allBufPtrs[numOutputBufs] = &allBufs[numOutputBufs];
+ streamIds[numOutputBufs] = request.inputBuffer.streamId;
+ }
+
+ for (size_t i = 0; i < numBufs; i++) {
+ buffer_handle_t buf = allBufs[i];
+ CirculatingBuffers& cbs = mCirculatingBuffers[streamIds[i]];
+ if (cbs.count(buf) == 0) {
+ // Register a newly seen buffer
+ buffer_handle_t importedBuf = buf;
+ sHandleImporter.importBuffer(importedBuf);
+ if (importedBuf == nullptr) {
+ ALOGE("%s: output buffer %zu is invalid!", __FUNCTION__, i);
+ return Status::INTERNAL_ERROR;
+ } else {
+ cbs[buf] = importedBuf;
+ }
+ }
+ allBufPtrs[i] = &cbs[buf];
+ }
+
+ // All buffers are imported. Now validate output buffer acquire fences
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ if (!sHandleImporter.importFence(
+ request.outputBuffers[i].acquireFence, allFences[i])) {
+ ALOGE("%s: output buffer %zu acquire fence is invalid", __FUNCTION__, i);
+ cleanupInflightFences(allFences, i);
+ return Status::INTERNAL_ERROR;
+ }
+ }
+
+ // Validate input buffer acquire fences
+ if (hasInputBuf) {
+ if (!sHandleImporter.importFence(
+ request.inputBuffer.acquireFence, allFences[numOutputBufs])) {
+ ALOGE("%s: input buffer acquire fence is invalid", __FUNCTION__);
+ cleanupInflightFences(allFences, numOutputBufs);
+ return Status::INTERNAL_ERROR;
+ }
+ }
+ return Status::OK;
+}
+
+void CameraDeviceSession::cleanupInflightFences(
+ hidl_vec<int>& allFences, size_t numFences) {
+ for (size_t j = 0; j < numFences; j++) {
+ sHandleImporter.closeFence(allFences[j]);
+ }
+}
+
+// Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow.
+Return<void> CameraDeviceSession::constructDefaultRequestSettings(
+ RequestTemplate type, constructDefaultRequestSettings_cb _hidl_cb) {
+ Status status = initStatus();
+ CameraMetadata outMetadata;
+ const camera_metadata_t *rawRequest;
+ if (status == Status::OK) {
+ ATRACE_BEGIN("camera3->construct_default_request_settings");
+ rawRequest = mDevice->ops->construct_default_request_settings(mDevice, (int) type);
+ ATRACE_END();
+ if (rawRequest == nullptr) {
+ ALOGI("%s: template %d is not supported on this camera device",
+ __FUNCTION__, type);
+ status = Status::ILLEGAL_ARGUMENT;
+ } else {
+ convertToHidl(rawRequest, &outMetadata);
+ }
+ }
+ _hidl_cb(status, outMetadata);
+ return Void();
+}
+
+Return<void> CameraDeviceSession::configureStreams(
+ const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb) {
+ Status status = initStatus();
+ HalStreamConfiguration outStreams;
+
+ // hold the inflight lock for entire configureStreams scope since there must not be any
+ // inflight request/results during stream configuration.
+ Mutex::Autolock _l(mInflightLock);
+ if (!mInflightBuffers.empty()) {
+ ALOGE("%s: trying to configureStreams while there are still %zu inflight buffers!",
+ __FUNCTION__, mInflightBuffers.size());
+ _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+ return Void();
+ }
+
+
+
+ if (status == Status::OK) {
+ camera3_stream_configuration_t stream_list;
+ hidl_vec<camera3_stream_t*> streams;
+
+ stream_list.operation_mode = (uint32_t) requestedConfiguration.operationMode;
+ stream_list.num_streams = requestedConfiguration.streams.size();
+ streams.resize(stream_list.num_streams);
+ stream_list.streams = streams.data();
+
+ for (uint32_t i = 0; i < stream_list.num_streams; i++) {
+ int id = requestedConfiguration.streams[i].id;
+
+ if (mStreamMap.count(id) == 0) {
+ Camera3Stream stream;
+ convertFromHidl(requestedConfiguration.streams[i], &stream);
+ mStreamMap[id] = stream;
+ mCirculatingBuffers.emplace(stream.mId, CirculatingBuffers{});
+ } else {
+ // width/height/format must not change, but usage/rotation might need to change
+ if (mStreamMap[id].stream_type !=
+ (int) requestedConfiguration.streams[i].streamType ||
+ mStreamMap[id].width != requestedConfiguration.streams[i].width ||
+ mStreamMap[id].height != requestedConfiguration.streams[i].height ||
+ mStreamMap[id].format != (int) requestedConfiguration.streams[i].format ||
+ mStreamMap[id].data_space != (android_dataspace_t)
+ requestedConfiguration.streams[i].dataSpace) {
+ ALOGE("%s: stream %d configuration changed!", __FUNCTION__, id);
+ _hidl_cb(Status::INTERNAL_ERROR, outStreams);
+ return Void();
+ }
+ mStreamMap[id].rotation = (int) requestedConfiguration.streams[i].rotation;
+ mStreamMap[id].usage = (uint32_t) requestedConfiguration.streams[i].usage;
+ }
+ streams[i] = &mStreamMap[id];
+ }
+
+ ATRACE_BEGIN("camera3->configure_streams");
+ status_t ret = mDevice->ops->configure_streams(mDevice, &stream_list);
+ ATRACE_END();
+
+ // delete unused streams, note we do this after adding new streams to ensure new stream
+ // will not have the same address as deleted stream, and HAL has a chance to reference
+ // the to be deleted stream in configure_streams call
+ for(auto it = mStreamMap.begin(); it != mStreamMap.end();) {
+ int id = it->first;
+ bool found = false;
+ for (const auto& stream : requestedConfiguration.streams) {
+ if (id == stream.id) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // Unmap all buffers of deleted stream
+ for (auto& pair : mCirculatingBuffers.at(id)) {
+ sHandleImporter.freeBuffer(pair.second);
+ }
+ mCirculatingBuffers[id].clear();
+ mCirculatingBuffers.erase(id);
+ it = mStreamMap.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ if (ret == -EINVAL) {
+ status = Status::ILLEGAL_ARGUMENT;
+ } else if (ret != OK) {
+ status = Status::INTERNAL_ERROR;
+ } else {
+ convertToHidl(stream_list, &outStreams);
+ }
+
+ }
+ _hidl_cb(status, outStreams);
+ return Void();
+}
+
+Return<Status> CameraDeviceSession::processCaptureRequest(const CaptureRequest& request) {
+ Status status = initStatus();
+ if (status != Status::OK) {
+ ALOGE("%s: camera init failed or disconnected", __FUNCTION__);
+ return status;
+ }
+
+ camera3_capture_request_t halRequest;
+ halRequest.frame_number = request.frameNumber;
+ bool converted = convertFromHidl(request.settings, &halRequest.settings);
+ if (!converted) {
+ ALOGE("%s: capture request settings metadata is corrupt!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ hidl_vec<buffer_handle_t*> allBufPtrs;
+ hidl_vec<int> allFences;
+ bool hasInputBuf = (request.inputBuffer.streamId != -1 &&
+ request.inputBuffer.buffer.getNativeHandle() != nullptr);
+ size_t numOutputBufs = request.outputBuffers.size();
+ size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
+ status = importRequest(request, allBufPtrs, allFences);
+ if (status != Status::OK) {
+ return status;
+ }
+
+ hidl_vec<camera3_stream_buffer_t> outHalBufs;
+ outHalBufs.resize(numOutputBufs);
+ {
+ Mutex::Autolock _l(mInflightLock);
+ if (hasInputBuf) {
+ auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber);
+ auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
+ convertFromHidl(
+ allBufPtrs[numOutputBufs], request.inputBuffer.status,
+ &mStreamMap[request.inputBuffer.streamId], allFences[numOutputBufs],
+ &bufCache);
+ halRequest.input_buffer = &bufCache;
+ } else {
+ halRequest.input_buffer = nullptr;
+ }
+
+ halRequest.num_output_buffers = numOutputBufs;
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber);
+ auto& bufCache = mInflightBuffers[key] = camera3_stream_buffer_t{};
+ convertFromHidl(
+ allBufPtrs[i], request.outputBuffers[i].status,
+ &mStreamMap[request.outputBuffers[i].streamId], allFences[i],
+ &bufCache);
+ outHalBufs[i] = bufCache;
+ }
+ halRequest.output_buffers = outHalBufs.data();
+ }
+
+ ATRACE_ASYNC_BEGIN("frame capture", request.frameNumber);
+ ATRACE_BEGIN("camera3->process_capture_request");
+ status_t ret = mDevice->ops->process_capture_request(mDevice, &halRequest);
+ ATRACE_END();
+ if (ret != OK) {
+ Mutex::Autolock _l(mInflightLock);
+ ALOGE("%s: HAL process_capture_request call failed!", __FUNCTION__);
+
+ cleanupInflightFences(allFences, numBufs);
+ if (hasInputBuf) {
+ auto key = std::make_pair(request.inputBuffer.streamId, request.frameNumber);
+ mInflightBuffers.erase(key);
+ }
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ auto key = std::make_pair(request.outputBuffers[i].streamId, request.frameNumber);
+ mInflightBuffers.erase(key);
+ }
+ return Status::INTERNAL_ERROR;
+ }
+
+ return Status::OK;
+}
+
+Return<Status> CameraDeviceSession::flush() {
+ Status status = initStatus();
+ if (status == Status::OK) {
+ // Flush is always supported on device 3.1 or later
+ status_t ret = mDevice->ops->flush(mDevice);
+ if (ret != OK) {
+ status = Status::INTERNAL_ERROR;
+ }
+ }
+ return status;
+}
+
+Return<void> CameraDeviceSession::close() {
+ Mutex::Autolock _l(mStateLock);
+ if (!mClosed) {
+ {
+ Mutex::Autolock _l(mInflightLock);
+ if (!mInflightBuffers.empty()) {
+ ALOGE("%s: trying to close while there are still %zu inflight buffers!",
+ __FUNCTION__, mInflightBuffers.size());
+ }
+ }
+
+ ATRACE_BEGIN("camera3->close");
+ mDevice->common.close(&mDevice->common);
+ ATRACE_END();
+
+ // free all imported buffers
+ for(auto& pair : mCirculatingBuffers) {
+ CirculatingBuffers& buffers = pair.second;
+ for (auto& p2 : buffers) {
+ sHandleImporter.freeBuffer(p2.second);
+ }
+ }
+
+ mClosed = true;
+ }
+ return Void();
+}
+
+/**
+ * Static callback forwarding methods from HAL to instance
+ */
+void CameraDeviceSession::sProcessCaptureResult(
+ const camera3_callback_ops *cb,
+ const camera3_capture_result *hal_result) {
+ CameraDeviceSession *d =
+ const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+
+ uint32_t frameNumber = hal_result->frame_number;
+ bool hasInputBuf = (hal_result->input_buffer != nullptr);
+ size_t numOutputBufs = hal_result->num_output_buffers;
+ size_t numBufs = numOutputBufs + (hasInputBuf ? 1 : 0);
+ Status status = Status::OK;
+ {
+ Mutex::Autolock _l(d->mInflightLock);
+ if (hasInputBuf) {
+ int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
+ // validate if buffer is inflight
+ auto key = std::make_pair(streamId, frameNumber);
+ if (d->mInflightBuffers.count(key) != 1) {
+ ALOGE("%s: input buffer for stream %d frame %d is not inflight!",
+ __FUNCTION__, streamId, frameNumber);
+ return;
+ }
+ }
+
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
+ // validate if buffer is inflight
+ auto key = std::make_pair(streamId, frameNumber);
+ if (d->mInflightBuffers.count(key) != 1) {
+ ALOGE("%s: output buffer for stream %d frame %d is not inflight!",
+ __FUNCTION__, streamId, frameNumber);
+ return;
+ }
+ }
+ }
+ // We don't need to validate/import fences here since we will be passing them to camera service
+ // within the scope of this function
+
+ CaptureResult result;
+ hidl_vec<native_handle_t*> releaseFences;
+ releaseFences.resize(numBufs);
+ result.frameNumber = frameNumber;
+ result.partialResult = hal_result->partial_result;
+ convertToHidl(hal_result->result, &result.result);
+ if (hasInputBuf) {
+ result.inputBuffer.streamId =
+ static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
+ result.inputBuffer.buffer = nullptr;
+ result.inputBuffer.status = (BufferStatus) hal_result->input_buffer->status;
+ // skip acquire fence since it's no use to camera service
+ if (hal_result->input_buffer->release_fence != -1) {
+ releaseFences[numOutputBufs] = native_handle_create(/*numFds*/1, /*numInts*/0);
+ releaseFences[numOutputBufs]->data[0] = hal_result->input_buffer->release_fence;
+ result.inputBuffer.releaseFence = releaseFences[numOutputBufs];
+ } else {
+ releaseFences[numOutputBufs] = nullptr;
+ }
+ } else {
+ result.inputBuffer.streamId = -1;
+ }
+
+ result.outputBuffers.resize(numOutputBufs);
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ result.outputBuffers[i].streamId =
+ static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
+ result.outputBuffers[i].buffer = nullptr;
+ result.outputBuffers[i].status = (BufferStatus) hal_result->output_buffers[i].status;
+ // skip acquire fence since it's of no use to camera service
+ if (hal_result->output_buffers[i].release_fence != -1) {
+ releaseFences[i] = native_handle_create(/*numFds*/1, /*numInts*/0);
+ releaseFences[i]->data[0] = hal_result->output_buffers[i].release_fence;
+ result.outputBuffers[i].releaseFence = releaseFences[i];
+ } else {
+ releaseFences[i] = nullptr;
+ }
+ }
+
+ // Free inflight record/fences.
+ // Do this before call back to camera service because camera service might jump to
+ // configure_streams right after the processCaptureResult call so we need to finish
+ // updating inflight queues first
+ {
+ Mutex::Autolock _l(d->mInflightLock);
+ if (hasInputBuf) {
+ int streamId = static_cast<Camera3Stream*>(hal_result->input_buffer->stream)->mId;
+ auto key = std::make_pair(streamId, frameNumber);
+ sHandleImporter.closeFence(d->mInflightBuffers[key].acquire_fence);
+ d->mInflightBuffers.erase(key);
+ }
+
+ for (size_t i = 0; i < numOutputBufs; i++) {
+ int streamId = static_cast<Camera3Stream*>(hal_result->output_buffers[i].stream)->mId;
+ auto key = std::make_pair(streamId, frameNumber);
+ sHandleImporter.closeFence(d->mInflightBuffers[key].acquire_fence);
+ d->mInflightBuffers.erase(key);
+ }
+
+ if (d->mInflightBuffers.empty()) {
+ ALOGV("%s: inflight buffer queue is now empty!", __FUNCTION__);
+ }
+ }
+
+ d->mCallback->processCaptureResult(result);
+
+ for (size_t i = 0; i < releaseFences.size(); i++) {
+ // We don't close the FD here as HAL needs to signal it later.
+ native_handle_delete(releaseFences[i]);
+ }
+}
+
+void CameraDeviceSession::sNotify(
+ const camera3_callback_ops *cb,
+ const camera3_notify_msg *msg) {
+ CameraDeviceSession *d =
+ const_cast<CameraDeviceSession*>(static_cast<const CameraDeviceSession*>(cb));
+ NotifyMsg hidlMsg;
+ convertToHidl(msg, &hidlMsg);
+ if (hidlMsg.type == (MsgType) CAMERA3_MSG_ERROR &&
+ hidlMsg.msg.error.errorStreamId != -1) {
+ if (d->mStreamMap.count(hidlMsg.msg.error.errorStreamId) != 1) {
+ ALOGE("%s: unknown stream ID %d reports an error!",
+ __FUNCTION__, hidlMsg.msg.error.errorStreamId);
+ }
+ return;
+ }
+ d->mCallback->notify(hidlMsg);
+}
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.2/default/CameraDeviceSession.h b/camera/device/3.2/default/CameraDeviceSession.h
new file mode 100644
index 0000000..498617e
--- /dev/null
+++ b/camera/device/3.2/default/CameraDeviceSession.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H
+
+#include <unordered_map>
+#include "hardware/camera_common.h"
+#include "hardware/camera3.h"
+#include "utils/Mutex.h"
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/3.2/ICameraDeviceSession.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+#include <include/convert.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+/**
+ * Function pointer types with C calling convention to
+ * use for HAL callback functions.
+ */
+extern "C" {
+ typedef void (callbacks_process_capture_result_t)(
+ const struct camera3_callback_ops *,
+ const camera3_capture_result_t *);
+
+ typedef void (callbacks_notify_t)(
+ const struct camera3_callback_ops *,
+ const camera3_notify_msg_t *);
+}
+
+struct CameraDeviceSession : public ICameraDeviceSession, private camera3_callback_ops {
+
+ CameraDeviceSession(camera3_device_t*, const sp<ICameraDeviceCallback>&);
+ ~CameraDeviceSession();
+ // Call by CameraDevice to dump active device states
+ void dumpState(const native_handle_t* fd);
+ // Caller must use this method to check if CameraDeviceSession ctor failed
+ bool isInitFailed() { return mInitFail; }
+ // Used by CameraDevice to signal external camera disconnected
+ void disconnect();
+ bool isClosed();
+
+ // Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow.
+ Return<void> constructDefaultRequestSettings(RequestTemplate type, constructDefaultRequestSettings_cb _hidl_cb) override;
+ Return<void> configureStreams(const StreamConfiguration& requestedConfiguration, configureStreams_cb _hidl_cb) override;
+ Return<Status> processCaptureRequest(const CaptureRequest& request) override;
+ Return<Status> flush() override;
+ Return<void> close() override;
+
+private:
+ // protecting mClosed/mDisconnected/mInitFail
+ mutable Mutex mStateLock;
+ // device is closed either
+ // - closed by user
+ // - init failed
+ // - camera disconnected
+ bool mClosed = false;
+
+ // Set by CameraDevice (when external camera is disconnected)
+ bool mDisconnected = false;
+
+ camera3_device_t* mDevice;
+ const sp<ICameraDeviceCallback> mCallback;
+ // Stream ID -> Camera3Stream cache
+ std::map<int, Camera3Stream> mStreamMap;
+
+ mutable Mutex mInflightLock; // protecting mInflightBuffers and mCirculatingBuffers
+ // (streamID, frameNumber) -> inflight buffer cache
+ std::map<std::pair<int, uint32_t>, camera3_stream_buffer_t> mInflightBuffers;
+
+ struct BufferHasher {
+ size_t operator()(const buffer_handle_t& buf) const {
+ if (buf == nullptr)
+ return 0;
+
+ size_t result = 1;
+ result = 31 * result + buf->numFds;
+ result = 31 * result + buf->numInts;
+ int length = buf->numFds + buf->numInts;
+ for (int i = 0; i < length; i++) {
+ result = 31 * result + buf->data[i];
+ }
+ return result;
+ }
+ };
+
+ struct BufferComparator {
+ bool operator()(const buffer_handle_t& buf1, const buffer_handle_t& buf2) const {
+ if (buf1->numFds == buf2->numFds && buf1->numInts == buf2->numInts) {
+ int length = buf1->numFds + buf1->numInts;
+ for (int i = 0; i < length; i++) {
+ if (buf1->data[i] != buf2->data[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ };
+
+ // buffers currently ciculating between HAL and camera service
+ // key: buffer_handle_t sent via HIDL interface
+ // value: imported buffer_handle_t
+ // Buffer will be imported during process_capture_request and will be freed
+ // when the its stream is deleted or camera device session is closed
+ typedef std::unordered_map<buffer_handle_t, buffer_handle_t,
+ BufferHasher, BufferComparator> CirculatingBuffers;
+ // Stream ID -> circulating buffers map
+ std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+ bool mInitFail;
+ bool initialize();
+
+ Status initStatus() const;
+
+ // Validate and import request's input buffer and acquire fence
+ Status importRequest(
+ const CaptureRequest& request,
+ hidl_vec<buffer_handle_t*>& allBufPtrs,
+ hidl_vec<int>& allFences);
+
+ static void cleanupInflightFences(
+ hidl_vec<int>& allFences, size_t numFences);
+
+ /**
+ * Static callback forwarding methods from HAL to instance
+ */
+ static callbacks_process_capture_result_t sProcessCaptureResult;
+ static callbacks_notify_t sNotify;
+};
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_2_CAMERADEVICE3SESSION_H
diff --git a/camera/device/3.2/default/convert.cpp b/camera/device/3.2/default/convert.cpp
new file mode 100644
index 0000000..35676df
--- /dev/null
+++ b/camera/device/3.2/default/convert.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.camera.device@3.2-convert-impl"
+#include <android/log.h>
+
+#include "include/convert.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::camera::device::V3_2::ConsumerUsageFlags;
+using ::android::hardware::camera::device::V3_2::ProducerUsageFlags;
+
+bool convertFromHidl(const CameraMetadata &src, const camera_metadata_t** dst) {
+ if (src.size() == 0) {
+ // Special case for null metadata
+ *dst = nullptr;
+ return true;
+ }
+
+ const uint8_t* data = src.data();
+ // sanity check the size of CameraMetadata match underlying camera_metadata_t
+ if (get_camera_metadata_size((camera_metadata_t*)data) != src.size()) {
+ ALOGE("%s: input CameraMetadata is corrupt!", __FUNCTION__);
+ return false;
+ }
+ *dst = (camera_metadata_t*) data;
+ return true;
+}
+
+// Note: existing data in dst will be gone. Caller still owns the memory of src
+void convertToHidl(const camera_metadata_t *src, CameraMetadata* dst) {
+ if (src == nullptr) {
+ return;
+ }
+ size_t size = get_camera_metadata_size(src);
+ dst->setToExternal((uint8_t *) src, size);
+ return;
+}
+
+void convertFromHidl(const Stream &src, Camera3Stream* dst) {
+ dst->mId = src.id;
+ dst->stream_type = (int) src.streamType;
+ dst->width = src.width;
+ dst->height = src.height;
+ dst->format = (int) src.format;
+ dst->data_space = (android_dataspace_t) src.dataSpace;
+ dst->rotation = (int) src.rotation;
+ dst->usage = (uint32_t) src.usage;
+ // Fields to be filled by HAL (max_buffers, priv) are initialized to 0
+ dst->max_buffers = 0;
+ dst->priv = 0;
+ return;
+}
+
+void convertToHidl(const Camera3Stream* src, HalStream* dst) {
+ dst->id = src->mId;
+ dst->overrideFormat = (PixelFormat) src->format;
+ dst->maxBuffers = src->max_buffers;
+ if (src->stream_type == CAMERA3_STREAM_OUTPUT) {
+ dst->consumerUsage = (ConsumerUsageFlags) 0;
+ dst->producerUsage = (ProducerUsageFlags) src->usage;
+ } else if (src->stream_type == CAMERA3_STREAM_INPUT) {
+ dst->producerUsage = (ProducerUsageFlags) 0;
+ dst->consumerUsage = (ConsumerUsageFlags) src->usage;
+ } else {
+ //Should not reach here per current HIDL spec, but we might end up adding
+ // bi-directional stream to HIDL.
+ ALOGW("%s: Stream type %d is not currently supported!",
+ __FUNCTION__, src->stream_type);
+ }
+}
+
+void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst) {
+ dst->streams.resize(src.num_streams);
+ for (uint32_t i = 0; i < src.num_streams; i++) {
+ convertToHidl(static_cast<Camera3Stream*>(src.streams[i]), &dst->streams[i]);
+ }
+ return;
+}
+
+void convertFromHidl(
+ buffer_handle_t* bufPtr, BufferStatus status, camera3_stream_t* stream, int acquireFence,
+ camera3_stream_buffer_t* dst) {
+ dst->stream = stream;
+ dst->buffer = bufPtr;
+ dst->status = (int) status;
+ dst->acquire_fence = acquireFence;
+ dst->release_fence = -1; // meant for HAL to fill in
+}
+
+void convertToHidl(const camera3_notify_msg* src, NotifyMsg* dst) {
+ dst->type = (MsgType) src->type;
+ switch (src->type) {
+ case CAMERA3_MSG_ERROR:
+ {
+ // The camera3_stream_t* must be the same as what wrapper HAL passed to conventional
+ // HAL, or the ID lookup will return garbage. Caller should validate the ID here is
+ // indeed one of active stream IDs
+ Camera3Stream* stream = static_cast<Camera3Stream*>(
+ src->message.error.error_stream);
+ dst->msg.error.frameNumber = src->message.error.frame_number;
+ dst->msg.error.errorStreamId = (stream != nullptr) ? stream->mId : -1;
+ dst->msg.error.errorCode = (ErrorCode) src->message.error.error_code;
+ }
+ break;
+ case CAMERA3_MSG_SHUTTER:
+ dst->msg.shutter.frameNumber = src->message.shutter.frame_number;
+ dst->msg.shutter.timestamp = src->message.shutter.timestamp;
+ break;
+ default:
+ ALOGE("%s: HIDL type converion failed. Unknown msg type 0x%x",
+ __FUNCTION__, src->type);
+ }
+ return;
+}
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.2/default/include/convert.h b/camera/device/3.2/default/include/convert.h
new file mode 100644
index 0000000..96891f0
--- /dev/null
+++ b/camera/device/3.2/default/include/convert.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_
+
+#define HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_
+
+#include <set>
+
+
+#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/camera/device/3.2/types.h>
+#include "hardware/camera3.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_2 {
+namespace implementation {
+
+// The camera3_stream_t sent to conventional HAL. Added mId fields to enable stream ID lookup
+// fromt a downcasted camera3_stream
+struct Camera3Stream : public camera3_stream {
+ int mId;
+};
+
+// *dst will point to the data owned by src, but src still owns the data after this call returns.
+bool convertFromHidl(const CameraMetadata &src, const camera_metadata_t** dst);
+void convertToHidl(const camera_metadata_t* src, CameraMetadata* dst);
+
+void convertFromHidl(const Stream &src, Camera3Stream* dst);
+void convertToHidl(const Camera3Stream* src, HalStream* dst);
+
+void convertFromHidl(
+ buffer_handle_t*, BufferStatus, camera3_stream_t*, int acquireFence, // inputs
+ camera3_stream_buffer_t* dst);
+
+void convertToHidl(const camera3_stream_configuration_t& src, HalStreamConfiguration* dst);
+
+// The camera3_stream_t* in src must be the same as what wrapper HAL passed to conventional
+// HAL, or the ID lookup will return garbage. Caller should validate the ID in ErrorMsg is
+// indeed one of active stream IDs
+void convertToHidl(const camera3_notify_msg* src, NotifyMsg* dst);
+
+} // namespace implementation
+} // namespace V3_2
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // HARDWARE_INTERFACES_CAMERA_DEVICE_V3_2_DEFAULT_INCLUDE_CONVERT_H_
diff --git a/camera/device/3.2/types.hal b/camera/device/3.2/types.hal
index a7ab4ab..1e0924c 100644
--- a/camera/device/3.2/types.hal
+++ b/camera/device/3.2/types.hal
@@ -403,7 +403,9 @@
*/
struct StreamBuffer {
/**
- * The ID of the stream this buffer is associated with
+ * The ID of the stream this buffer is associated with. -1 indicates an
+ * invalid (empty) StreamBuffer, in which case buffer must also point to
+ * null.
*/
int32_t streamId;
@@ -605,7 +607,7 @@
};
/**
- * MotifyMsg:
+ * NotifyMsg:
*
* The message structure sent to ICameraDevice3Callback::notify()
*/
diff --git a/camera/provider/2.4/ICameraProvider.hal b/camera/provider/2.4/ICameraProvider.hal
index 564167b..3015b7d 100644
--- a/camera/provider/2.4/ICameraProvider.hal
+++ b/camera/provider/2.4/ICameraProvider.hal
@@ -120,6 +120,30 @@
generates (Status status, vec<string> cameraDeviceNames);
/**
+ * isSetTorchModeSupported:
+ *
+ * Returns if the camera devices known to this camera provider support
+ * setTorchMode API or not. If the provider does not support setTorchMode
+ * API, calling to setTorchMode will return METHOD_NOT_SUPPORTED.
+ *
+ * Note that not every camera device has a flash unit, so even this API
+ * returns true, setTorchMode call might still fail due to the camera device
+ * does not have a flash unit. In such case, the returned status will be
+ * OPERATION_NOT_SUPPORTED.
+ *
+ * @return status Status code for the operation, one of:
+ * OK:
+ * On a succesful call
+ * INTERNAL_ERROR:
+ * Torch API support cannot be queried. This may be due to
+ * a failure to initialize the camera subsystem, for example.
+ * @return support Whether the camera devices known to this provider
+ * supports setTorchMode API or not.
+ *
+ */
+ isSetTorchModeSupported() generates (Status status, bool support);
+
+ /**
* getCameraDeviceInterface_VN_x:
*
* Return a android.hardware.camera.device@N.x/ICameraDevice interface for
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
new file mode 100644
index 0000000..f28c9cd
--- /dev/null
+++ b/camera/provider/2.4/default/Android.bp
@@ -0,0 +1,23 @@
+cc_library_shared {
+ name: "android.hardware.camera.provider@2.4-impl",
+ relative_install_path: "hw",
+ srcs: ["CameraProvider.cpp"],
+ shared_libs: [
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "libcutils",
+ "android.hardware.camera.device@1.0",
+ "android.hardware.camera.device@3.2",
+ "android.hardware.camera.device@3.2-impl",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.common@1.0",
+ "liblog",
+ "libhardware",
+ "libcamera_metadata"
+ ],
+ static_libs: [
+ "android.hardware.camera.common@1.0-helper"
+ ]
+}
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
new file mode 100644
index 0000000..9617d8d
--- /dev/null
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamProvider@2.4-impl"
+#include <android/log.h>
+
+#include <regex>
+
+#include "CameraProvider.h"
+#include "CameraDevice.h"
+#include <string.h>
+#include <utils/Trace.h>
+
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_4 {
+namespace implementation {
+
+namespace {
+const char *kLegacyProviderName = "legacy/0";
+// "device@<version>/legacy/<id>"
+const std::regex kDeviceNameRE("device@([0-9]+\\.[0-9]+)/legacy/(.+)");
+const char *kHAL3_2 = "3.2";
+const char *kHAL1_0 = "1.0";
+const int kMaxCameraDeviceNameLen = 128;
+const int kMaxCameraIdLen = 16;
+
+} // anonymous namespace
+
+using ::android::hardware::camera::common::V1_0::CameraMetadataType;
+using ::android::hardware::camera::common::V1_0::Status;
+
+/**
+ * static callback forwarding methods from HAL to instance
+ */
+void CameraProvider::sCameraDeviceStatusChange(
+ const struct camera_module_callbacks* callbacks,
+ int camera_id,
+ int new_status) {
+ ALOGI("%s++", __FUNCTION__);
+ sp<CameraProvider> cp = const_cast<CameraProvider*>(
+ static_cast<const CameraProvider*>(callbacks));
+
+ if (cp == nullptr) {
+ ALOGE("%s: callback ops is null", __FUNCTION__);
+ return;
+ }
+
+ ALOGI("%s resolved provider %p", __FUNCTION__, cp.get());
+
+ Mutex::Autolock _l(cp->mCbLock);
+ char cameraId[kMaxCameraIdLen];
+ snprintf(cameraId, sizeof(cameraId), "%d", camera_id);
+ std::string cameraIdStr(cameraId);
+ cp->mCameraStatusMap[cameraIdStr] = (camera_device_status_t) new_status;
+ if (cp->mCallbacks != nullptr) {
+ CameraDeviceStatus status = (CameraDeviceStatus) new_status;
+ for (auto const& deviceNamePair : cp->mCameraDeviceNames) {
+ if (cameraIdStr.compare(deviceNamePair.first) == 0) {
+ cp->mCallbacks->cameraDeviceStatusChange(
+ deviceNamePair.second, status);
+ }
+ }
+ }
+ ALOGI("%s--", __FUNCTION__);
+}
+
+void CameraProvider::sTorchModeStatusChange(
+ const struct camera_module_callbacks* callbacks,
+ const char* camera_id,
+ int new_status) {
+ ALOGI("%s++", __FUNCTION__);
+ sp<CameraProvider> cp = const_cast<CameraProvider*>(
+ static_cast<const CameraProvider*>(callbacks));
+
+ if (cp == nullptr) {
+ ALOGE("%s: callback ops is null", __FUNCTION__);
+ return;
+ }
+
+ ALOGI("%s resolved provider %p", __FUNCTION__, cp.get());
+
+ Mutex::Autolock _l(cp->mCbLock);
+ if (cp->mCallbacks != nullptr) {
+ std::string cameraIdStr(camera_id);
+ TorchModeStatus status = (TorchModeStatus) new_status;
+ for (auto const& deviceNamePair : cp->mCameraDeviceNames) {
+ if (cameraIdStr.compare(deviceNamePair.first) == 0) {
+ cp->mCallbacks->torchModeStatusChange(
+ deviceNamePair.second, status);
+ }
+ }
+ }
+ ALOGI("%s--", __FUNCTION__);
+}
+
+Status CameraProvider::getHidlStatus(int status) {
+ switch (status) {
+ case 0: return Status::OK;
+ case -ENODEV: return Status::INTERNAL_ERROR;
+ case -EINVAL: return Status::ILLEGAL_ARGUMENT;
+ default:
+ ALOGE("%s: unknown HAL status code %d", __FUNCTION__, status);
+ return Status::INTERNAL_ERROR;
+ }
+}
+
+bool CameraProvider::matchDeviceName(const hidl_string& deviceName, std::smatch& sm) {
+ std::string deviceNameStd(deviceName.c_str());
+ return std::regex_match(deviceNameStd, sm, kDeviceNameRE);
+}
+
+std::string CameraProvider::getLegacyCameraId(const hidl_string& deviceName) {
+ std::smatch sm;
+ bool match = matchDeviceName(deviceName, sm);
+ if (!match) {
+ return std::string("");
+ }
+ return sm[2];
+}
+
+int CameraProvider::getCameraDeviceVersion(const hidl_string& deviceName) {
+ std::smatch sm;
+ bool match = matchDeviceName(deviceName, sm);
+ if (!match) {
+ return -1;
+ }
+ if (sm[1].compare(kHAL3_2) == 0) {
+ // maybe switched to 3.4 or define the hidl version enum later
+ return CAMERA_DEVICE_API_VERSION_3_2;
+ } else if (sm[1].compare(kHAL1_0) == 0) {
+ return CAMERA_DEVICE_API_VERSION_1_0;
+ }
+ return 0;
+}
+
+std::string CameraProvider::getHidlDeviceName(
+ std::string cameraId, int deviceVersion) {
+ // Maybe consider create a version check method and SortedVec to speed up?
+ if (deviceVersion != CAMERA_DEVICE_API_VERSION_1_0 &&
+ deviceVersion != CAMERA_DEVICE_API_VERSION_3_2 &&
+ deviceVersion != CAMERA_DEVICE_API_VERSION_3_3 &&
+ deviceVersion != CAMERA_DEVICE_API_VERSION_3_4 ) {
+ return hidl_string("");
+ }
+ const char* versionStr = (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) ? kHAL1_0 : kHAL3_2;
+ char deviceName[kMaxCameraDeviceNameLen];
+ snprintf(deviceName, sizeof(deviceName), "device@%s/legacy/%s",
+ versionStr, cameraId.c_str());
+ return deviceName;
+}
+
+CameraProvider::CameraProvider() :
+ camera_module_callbacks_t({sCameraDeviceStatusChange,
+ sTorchModeStatusChange}) {
+ mInitFailed = initialize();
+}
+
+CameraProvider::~CameraProvider() {}
+
+bool CameraProvider::initialize() {
+ camera_module_t *rawModule;
+ int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
+ (const hw_module_t **)&rawModule);
+ if (err < 0) {
+ ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err));
+ return true;
+ }
+
+ mModule = new CameraModule(rawModule);
+ err = mModule->init();
+ if (err != OK) {
+ ALOGE("Could not initialize camera HAL module: %d (%s)", err,
+ strerror(-err));
+ mModule.clear();
+ return true;
+ }
+ ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());
+
+ mNumberOfLegacyCameras = mModule->getNumberOfCameras();
+ for (int i = 0; i < mNumberOfLegacyCameras; i++) {
+ char cameraId[kMaxCameraIdLen];
+ snprintf(cameraId, sizeof(cameraId), "%d", i);
+ std::string cameraIdStr(cameraId);
+ mCameraStatusMap[cameraIdStr] = CAMERA_DEVICE_STATUS_PRESENT;
+ mCameraIds.add(cameraIdStr);
+
+ // initialize mCameraDeviceNames and mOpenLegacySupported
+ mOpenLegacySupported[cameraIdStr] = false;
+ int deviceVersion = mModule->getDeviceVersion(i);
+ mCameraDeviceNames.add(
+ std::make_pair(cameraIdStr,
+ getHidlDeviceName(cameraIdStr, deviceVersion)));
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 &&
+ mModule->isOpenLegacyDefined()) {
+ // try open_legacy to see if it actually works
+ struct hw_device_t* halDev = nullptr;
+ int ret = mModule->openLegacy(cameraId, CAMERA_DEVICE_API_VERSION_1_0, &halDev);
+ if (ret == 0) {
+ mOpenLegacySupported[cameraIdStr] = true;
+ halDev->close(halDev);
+ mCameraDeviceNames.add(
+ std::make_pair(cameraIdStr,
+ getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0)));
+ } else if (ret == -EBUSY || ret == -EUSERS) {
+ // Looks like this provider instance is not initialized during
+ // system startup and there are other camera users already.
+ // Not a good sign but not fatal.
+ ALOGW("%s: open_legacy try failed!", __FUNCTION__);
+ }
+ }
+ }
+
+ // Setup vendor tags here so HAL can setup vendor keys in camera characteristics
+ VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+ bool setupSucceed = setUpVendorTags();
+ return !setupSucceed; // return flag here is mInitFailed
+}
+
+bool CameraProvider::setUpVendorTags() {
+ ATRACE_CALL();
+ vendor_tag_ops_t vOps = vendor_tag_ops_t();
+
+ // Check if vendor operations have been implemented
+ if (!mModule->isVendorTagDefined()) {
+ ALOGI("%s: No vendor tags defined for this device.", __FUNCTION__);
+ return false;
+ }
+
+ mModule->getVendorTagOps(&vOps);
+
+ // Ensure all vendor operations are present
+ if (vOps.get_tag_count == nullptr || vOps.get_all_tags == nullptr ||
+ vOps.get_section_name == nullptr || vOps.get_tag_name == nullptr ||
+ vOps.get_tag_type == nullptr) {
+ ALOGE("%s: Vendor tag operations not fully defined. Ignoring definitions."
+ , __FUNCTION__);
+ return false;
+ }
+
+ // Read all vendor tag definitions into a descriptor
+ sp<VendorTagDescriptor> desc;
+ status_t res;
+ if ((res = VendorTagDescriptor::createDescriptorFromOps(&vOps, /*out*/desc))
+ != OK) {
+ ALOGE("%s: Could not generate descriptor from vendor tag operations,"
+ "received error %s (%d). Camera clients will not be able to use"
+ "vendor tags", __FUNCTION__, strerror(res), res);
+ return false;
+ }
+
+ // Set the global descriptor to use with camera metadata
+ VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+ const SortedVector<String8>* sectionNames = desc->getAllSectionNames();
+ size_t numSections = sectionNames->size();
+ std::vector<std::vector<VendorTag>> tagsBySection(numSections);
+ int tagCount = desc->getTagCount();
+ std::vector<uint32_t> tags(tagCount);
+ desc->getTagArray(tags.data());
+ for (int i = 0; i < tagCount; i++) {
+ VendorTag vt;
+ vt.tagId = tags[i];
+ vt.tagName = desc->getTagName(tags[i]);
+ vt.tagType = (CameraMetadataType) desc->getTagType(tags[i]);
+ ssize_t sectionIdx = desc->getSectionIndex(tags[i]);
+ tagsBySection[sectionIdx].push_back(vt);
+ }
+ mVendorTagSections.resize(numSections);
+ for (size_t s = 0; s < numSections; s++) {
+ mVendorTagSections[s].sectionName = (*sectionNames)[s].string();
+ mVendorTagSections[s].tags = tagsBySection[s];
+ }
+ return true;
+}
+
+// Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
+Return<Status> CameraProvider::setCallback(const sp<ICameraProviderCallback>& callback) {
+ {
+ Mutex::Autolock _l(mCbLock);
+ mCallbacks = callback;
+ } // release lock here because HAL might send callbacks in setCallbacks call
+ return getHidlStatus(mModule->setCallbacks(this));
+}
+
+Return<void> CameraProvider::getVendorTags(getVendorTags_cb _hidl_cb) {
+ _hidl_cb(Status::OK, mVendorTagSections);
+ return Void();
+}
+
+Return<void> CameraProvider::getCameraIdList(getCameraIdList_cb _hidl_cb) {
+ std::vector<hidl_string> deviceNameList;
+ for (auto const& deviceNamePair : mCameraDeviceNames) {
+ if (mCameraStatusMap[deviceNamePair.first] == CAMERA_DEVICE_STATUS_PRESENT) {
+ deviceNameList.push_back(deviceNamePair.second);
+ }
+ }
+ hidl_vec<hidl_string> hidlDeviceNameList(deviceNameList);
+ _hidl_cb(Status::OK, hidlDeviceNameList);
+ return Void();
+}
+
+Return<void> CameraProvider::isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) {
+ bool support = mModule->isSetTorchModeSupported();
+ _hidl_cb (Status::OK, support);
+ return Void();
+}
+
+Return<void> CameraProvider::getCameraDeviceInterface_V1_x(
+ const hidl_string& /*cameraDeviceName*/, getCameraDeviceInterface_V1_x_cb /*_hidl_cb*/) {
+ // TODO implement after device 1.0 is implemented
+ return Void();
+}
+
+Return<void> CameraProvider::getCameraDeviceInterface_V3_x(
+ const hidl_string& cameraDeviceName, getCameraDeviceInterface_V3_x_cb _hidl_cb) {
+ std::smatch sm;
+ bool match = matchDeviceName(cameraDeviceName, sm);
+ if (!match) {
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ std::string cameraId = sm[2];
+ std::string deviceVersion = sm[1];
+ std::string deviceName(cameraDeviceName.c_str());
+ ssize_t index = mCameraDeviceNames.indexOf(std::make_pair(cameraId, deviceName));
+ if (index == NAME_NOT_FOUND) { // Either an illegal name or a device version mismatch
+ Status status = Status::OK;
+ ssize_t idx = mCameraIds.indexOf(cameraId);
+ if (idx == NAME_NOT_FOUND) {
+ ALOGE("%s: cannot find camera %s!", __FUNCTION__, cameraId.c_str());
+ status = Status::ILLEGAL_ARGUMENT;
+ } else { // invalid version
+ ALOGE("%s: camera device %s does not support version %s!",
+ __FUNCTION__, cameraId.c_str(), deviceVersion.c_str());
+ status = Status::OPERATION_NOT_SUPPORTED;
+ }
+ _hidl_cb(status, nullptr);
+ return Void();
+ }
+
+ if (mCameraStatusMap.count(cameraId) == 0 ||
+ mCameraStatusMap[cameraId] != CAMERA_DEVICE_STATUS_PRESENT) {
+ _hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
+ return Void();
+ }
+
+ // TODO: we also need to keep a wp list of all generated devices to notify
+ // devices of device present status change, but then each device might
+ // need a sp<provider> to keep provider alive until all device closed?
+ // Problem: do we have external camera products to test this?
+ sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> device =
+ new android::hardware::camera::device::V3_2::implementation::CameraDevice(
+ mModule, cameraId, mCameraDeviceNames);
+
+ if (device == nullptr) {
+ ALOGE("%s: cannot allocate camera device for id %s", __FUNCTION__, cameraId.c_str());
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+
+ if (device->isInitFailed()) {
+ ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
+ device = nullptr;
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
+
+ _hidl_cb (Status::OK, device);
+ return Void();
+}
+
+ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) {
+ if (strcmp(name, kLegacyProviderName) != 0) {
+ return nullptr;
+ }
+ CameraProvider* provider = new CameraProvider();
+ if (provider == nullptr) {
+ ALOGE("%s: cannot allocate camera provider!", __FUNCTION__);
+ return nullptr;
+ }
+ if (provider->isInitFailed()) {
+ ALOGE("%s: camera provider init failed!", __FUNCTION__);
+ delete provider;
+ return nullptr;
+ }
+ return provider;
+}
+
+} // namespace implementation
+} // namespace V2_4
+} // namespace provider
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/CameraProvider.h
new file mode 100644
index 0000000..8497ff3
--- /dev/null
+++ b/camera/provider/2.4/default/CameraProvider.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
+#define ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
+
+#include "hardware/camera_common.h"
+#include "utils/Mutex.h"
+#include "utils/SortedVector.h"
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+#include "CameraModule.h"
+#include "VendorTagDescriptor.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace provider {
+namespace V2_4 {
+namespace implementation {
+
+using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::TorchModeStatus;
+using ::android::hardware::camera::common::V1_0::VendorTag;
+using ::android::hardware::camera::common::V1_0::VendorTagSection;
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
+using ::android::hardware::camera::provider::V2_4::ICameraProvider;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+struct CameraProvider : public ICameraProvider, public camera_module_callbacks_t {
+ CameraProvider();
+ ~CameraProvider();
+
+ // Caller must use this method to check if CameraProvider ctor failed
+ bool isInitFailed() { return mInitFailed; }
+
+ // Methods from ::android::hardware::camera::provider::V2_4::ICameraProvider follow.
+ Return<Status> setCallback(const sp<ICameraProviderCallback>& callback) override;
+ Return<void> getVendorTags(getVendorTags_cb _hidl_cb) override;
+ Return<void> getCameraIdList(getCameraIdList_cb _hidl_cb) override;
+ Return<void> isSetTorchModeSupported(isSetTorchModeSupported_cb _hidl_cb) override;
+ Return<void> getCameraDeviceInterface_V1_x(
+ const hidl_string& cameraDeviceName,
+ getCameraDeviceInterface_V1_x_cb _hidl_cb) override;
+ Return<void> getCameraDeviceInterface_V3_x(
+ const hidl_string& cameraDeviceName,
+ getCameraDeviceInterface_V3_x_cb _hidl_cb) override;
+
+private:
+ Mutex mCbLock;
+ sp<ICameraProviderCallback> mCallbacks = nullptr;
+
+ sp<CameraModule> mModule;
+
+ int mNumberOfLegacyCameras;
+ std::map<std::string, camera_device_status_t> mCameraStatusMap; // camera id -> status
+ std::map<std::string, bool> mOpenLegacySupported; // camera id -> open_legacy HAL1.0 supported
+ SortedVector<std::string> mCameraIds; // the "0"/"1" legacy camera Ids
+ // (cameraId string, hidl device name) pairs
+ SortedVector<std::pair<std::string, std::string>> mCameraDeviceNames;
+
+ // Must be queried before using any APIs.
+ // APIs will only work when this returns true
+ bool mInitFailed;
+ bool initialize();
+
+ hidl_vec<VendorTagSection> mVendorTagSections;
+ bool setUpVendorTags();
+
+ // extract legacy camera ID/device version from a HIDL device name
+ static bool matchDeviceName(const hidl_string& deviceName, std::smatch& sm);
+ static std::string getLegacyCameraId(const hidl_string& deviceName);
+ static int getCameraDeviceVersion(const hidl_string& deviceName);
+
+ // create HIDL device name from camera ID and device version
+ static std::string getHidlDeviceName(std::string cameraId, int deviceVersion);
+
+ // convert conventional HAL status to HIDL Status
+ static Status getHidlStatus(int);
+
+ // static callback forwarding methods
+ static void sCameraDeviceStatusChange(
+ const struct camera_module_callbacks* callbacks,
+ int camera_id,
+ int new_status);
+ static void sTorchModeStatusChange(
+ const struct camera_module_callbacks* callbacks,
+ const char* camera_id,
+ int new_status);
+};
+
+extern "C" ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name);
+
+} // namespace implementation
+} // namespace V2_4
+} // namespace provider
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_PROVIDER_V2_4_CAMERAPROVIDER_H
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
new file mode 100644
index 0000000..4947c17
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "camera_hidl_hal_test",
+ gtest: true,
+ srcs: ["camera_hidl_hal_test.cpp"],
+ shared_libs: [
+ "liblog",
+ "libhidlbase",
+ "libhidltransport",
+ "libcutils",
+ "libutils",
+ "android.hardware.camera.provider@2.4",
+ "android.hardware.camera.device@3.2",
+ "libcamera_metadata"
+ ],
+ static_libs: ["libgtest"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+}
diff --git a/camera/provider/2.4/vts/functional/camera_hidl_hal_test.cpp b/camera/provider/2.4/vts/functional/camera_hidl_hal_test.cpp
new file mode 100644
index 0000000..0eb291c
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/camera_hidl_hal_test.cpp
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "camera_hidl_hal_test"
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/log.h>
+#include <gtest/gtest.h>
+#include <regex>
+#include "system/camera_metadata.h"
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::sp;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::TorchModeStatus;
+using ::android::hardware::camera::provider::V2_4::ICameraProvider;
+using ::android::hardware::camera::provider::V2_4::ICameraProviderCallback;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+
+#define CAMERA_PASSTHROUGH_SERVICE_NAME "legacy/0"
+
+namespace {
+ // "device@<version>/legacy/<id>"
+ const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/legacy/(.+)";
+ const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
+ const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
+ const char *kHAL3_2 = "3.2";
+ const char *kHAL1_0 = "1.0";
+
+ bool matchDeviceName(const hidl_string& deviceName, std::smatch& sm) {
+ std::regex e(kDeviceNameRE);
+ std::string deviceNameStd(deviceName.c_str());
+ return std::regex_match(deviceNameStd, sm, e);
+ }
+
+ int getCameraDeviceVersion(const hidl_string& deviceName) {
+ std::smatch sm;
+ bool match = matchDeviceName(deviceName, sm);
+ if (!match) {
+ return -1;
+ }
+ if (sm[1].compare(kHAL3_2) == 0) {
+ // maybe switched to 3.4 or define the hidl version enumlater
+ return CAMERA_DEVICE_API_VERSION_3_2;
+ } else if (sm[1].compare(kHAL1_0) == 0) {
+ return CAMERA_DEVICE_API_VERSION_1_0;
+ }
+ return 0;
+ }
+}
+
+// Test environment for camera
+class CameraHidlEnvironment : public ::testing::Environment {
+public:
+ // get the test environment singleton
+ static CameraHidlEnvironment* Instance() {
+ static CameraHidlEnvironment* instance = new CameraHidlEnvironment;
+ return instance;
+ }
+
+ virtual void SetUp() override;
+ virtual void TearDown() override;
+
+ sp<ICameraProvider> mProvider;
+
+private:
+ CameraHidlEnvironment() {}
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(CameraHidlEnvironment);
+};
+
+void CameraHidlEnvironment::SetUp() {
+ // TODO: test the binderized mode
+ mProvider = ICameraProvider::getService(CAMERA_PASSTHROUGH_SERVICE_NAME, true);
+ // TODO: handle the device doesn't have any camera case
+ ALOGI_IF(mProvider, "provider is not nullptr, %p", mProvider.get());
+ ASSERT_NE(mProvider, nullptr);
+}
+
+void CameraHidlEnvironment::TearDown() {
+ ALOGI("TearDown CameraHidlEnvironment");
+}
+
+// The main test class for camera HIDL HAL.
+class CameraHidlTest : public ::testing::Test {
+public:
+ virtual void SetUp() override {}
+ virtual void TearDown() override {}
+
+ hidl_vec<hidl_string> getCameraDeviceNames();
+
+ struct EmptyDeviceCb : public ICameraDeviceCallback {
+ virtual Return<void> processCaptureResult(const CaptureResult& /*result*/) override {
+ ALOGI("processCaptureResult callback");
+ ADD_FAILURE(); // Empty callback should not reach here
+ return Void();
+ }
+
+ virtual Return<void> notify(const NotifyMsg& /*msg*/) override {
+ ALOGI("notify callback");
+ ADD_FAILURE(); // Empty callback should not reach here
+ return Void();
+ }
+ };
+};
+
+hidl_vec<hidl_string> CameraHidlTest::getCameraDeviceNames() {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames;
+ env->mProvider->getCameraIdList(
+ [&](auto status, const auto& idList) {
+ ALOGI("getCameraIdList returns status:%d", (int)status);
+ for (size_t i = 0; i < idList.size(); i++) {
+ ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str());
+ }
+ ASSERT_EQ(Status::OK, status);
+ cameraDeviceNames = idList;
+ });
+ return cameraDeviceNames;
+}
+
+// Test if ICameraProvider::isTorchModeSupported returns Status::OK
+TEST_F(CameraHidlTest, isTorchModeSupported) {
+ CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
+ [&](auto status, bool support) {
+ ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
+ (int)status, support);
+ ASSERT_EQ(Status::OK, status);
+ });
+}
+
+// TODO: consider removing this test if getCameraDeviceNames() has the same coverage
+TEST_F(CameraHidlTest, getCameraIdList) {
+ CameraHidlEnvironment::Instance()->mProvider->getCameraIdList(
+ [&](auto status, const auto& idList) {
+ ALOGI("getCameraIdList returns status:%d", (int)status);
+ for (size_t i = 0; i < idList.size(); i++) {
+ ALOGI("Camera Id[%zu] is %s", i, idList[i].c_str());
+ }
+ ASSERT_EQ(Status::OK, status);
+ // This is true for internal camera provider.
+ // Not necessary hold for external cameras providers
+ ASSERT_GT(idList.size(), 0u);
+ });
+}
+
+// Test if ICameraProvider::getVendorTags returns Status::OK
+TEST_F(CameraHidlTest, getVendorTags) {
+ CameraHidlEnvironment::Instance()->mProvider->getVendorTags(
+ [&](auto status, const auto& vendorTagSecs) {
+ ALOGI("getVendorTags returns status:%d numSections %zu",
+ (int)status, vendorTagSecs.size());
+ for (size_t i = 0; i < vendorTagSecs.size(); i++) {
+ ALOGI("Vendor tag section %zu name %s",
+ i, vendorTagSecs[i].sectionName.c_str());
+ for (size_t j = 0; j < vendorTagSecs[i].tags.size(); j++) {
+ const auto& tag = vendorTagSecs[i].tags[j];
+ ALOGI("Vendor tag id %u name %s type %d",
+ tag.tagId,
+ tag.tagName.c_str(),
+ (int) tag.tagType);
+ }
+ }
+ ASSERT_EQ(Status::OK, status);
+ });
+}
+
+// Test if ICameraProvider::setCallback returns Status::OK
+TEST_F(CameraHidlTest, setCallback) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ struct ProviderCb : public ICameraProviderCallback {
+ virtual Return<void> cameraDeviceStatusChange(
+ const hidl_string& cameraDeviceName,
+ CameraDeviceStatus newStatus) override {
+ ALOGI("camera device status callback name %s, status %d",
+ cameraDeviceName.c_str(), (int) newStatus);
+ return Void();
+ }
+
+ virtual Return<void> torchModeStatusChange(
+ const hidl_string& cameraDeviceName,
+ TorchModeStatus newStatus) override {
+ ALOGI("Torch mode status callback name %s, status %d",
+ cameraDeviceName.c_str(), (int) newStatus);
+ return Void();
+ }
+ };
+ sp<ProviderCb> cb = new ProviderCb;
+ auto status = env->mProvider->setCallback(cb);
+ ASSERT_EQ(Status::OK, status);
+ // TODO: right now no callbacks are fired because there is no external camera
+ // or torch mode change. Need to test torch API in CameraDevice test later.
+}
+
+// Test if ICameraProvider::getCameraDeviceInterface_V3_x returns Status::OK and non-null device
+TEST_F(CameraHidlTest, getCameraDeviceInterface_V3_x) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device3_2) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device3_2, nullptr);
+ });
+ }
+ }
+}
+
+TEST_F(CameraHidlTest, getResourceCost) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("getResourceCost: Testing camera device %s", name.c_str());
+ env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+
+ device3_2->getResourceCost(
+ [&](auto status, const auto& resourceCost) {
+ ALOGI("getResourceCost returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ALOGI(" Resource cost is %d", resourceCost.resourceCost);
+ ASSERT_LE(resourceCost.resourceCost, 100u);
+ for (const auto& name : resourceCost.conflictingDevices) {
+ ALOGI(" Conflicting device: %s", name.c_str());
+ }
+ });
+ }
+ }
+}
+
+TEST_F(CameraHidlTest, getCameraCharacteristics) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
+ env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+
+ device3_2->getCameraCharacteristics(
+ [&](auto status, const auto& chars) {
+ ALOGI("getCameraCharacteristics returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ const camera_metadata_t* metadata = (camera_metadata_t*) chars.data();
+ size_t expectedSize = chars.size();
+ ASSERT_EQ(0, validate_camera_metadata_structure(metadata, &expectedSize));
+ size_t entryCount = get_camera_metadata_entry_count(metadata);
+ // TODO: we can do better than 0 here. Need to check how many required
+ // characteristics keys we've defined.
+ ASSERT_GT(entryCount, 0u);
+ ALOGI("getCameraCharacteristics metadata entry count is %zu", entryCount);
+ });
+ }
+ }
+}
+
+TEST_F(CameraHidlTest, setTorchMode) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+ bool torchControlSupported = false;
+
+ CameraHidlEnvironment::Instance()->mProvider->isSetTorchModeSupported(
+ [&](auto status, bool support) {
+ ALOGI("isSetTorchModeSupported returns status:%d supported:%d",
+ (int)status, support);
+ ASSERT_EQ(Status::OK, status);
+ torchControlSupported = support;
+ });
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("setTorchMode: Testing camera device %s", name.c_str());
+ env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+
+ Status status = device3_2->setTorchMode(TorchMode::ON);
+ ALOGI("setTorchMode return status %d", (int)status);
+ if (!torchControlSupported) {
+ ASSERT_EQ(Status::METHOD_NOT_SUPPORTED, status);
+ } else {
+ ASSERT_TRUE(status == Status::OK || status == Status::OPERATION_NOT_SUPPORTED);
+ if (status == Status::OK) {
+ status = device3_2->setTorchMode(TorchMode::OFF);
+ ASSERT_EQ(Status::OK, status);
+ }
+ }
+ }
+ }
+}
+
+TEST_F(CameraHidlTest, dumpState) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("dumpState: Testing camera device %s", name.c_str());
+ env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+
+ native_handle_t* raw_handle = native_handle_create(1, 0);
+ raw_handle->data[0] = 1; // std out
+ hidl_handle handle = raw_handle;
+ device3_2->dumpState(handle);
+ native_handle_delete(raw_handle);
+ }
+ }
+}
+
+// Open, dumpStates, then close
+TEST_F(CameraHidlTest, openClose) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("openClose: Testing camera device %s", name.c_str());
+ env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+
+ sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
+ sp<ICameraDeviceSession> session;
+ device3_2->open(
+ cb,
+ [&](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ session = newSession;
+ });
+
+ native_handle_t* raw_handle = native_handle_create(1, 0);
+ raw_handle->data[0] = 1; // std out
+ hidl_handle handle = raw_handle;
+ device3_2->dumpState(handle);
+ native_handle_delete(raw_handle);
+
+ session->close();
+ // TODO: test all session API calls return INTERNAL_ERROR after close
+ // TODO: keep a wp copy here and verify session cannot be promoted out of this scope
+ }
+ }
+}
+
+TEST_F(CameraHidlTest, constructDefaultRequestSettings) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("constructDefaultRequestSettings: Testing camera device %s", name.c_str());
+ env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+
+ sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
+ sp<ICameraDeviceSession> session;
+ device3_2->open(
+ cb,
+ [&](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ session = newSession;
+ });
+
+ for (uint32_t t = (uint32_t) RequestTemplate::PREVIEW;
+ t <= (uint32_t) RequestTemplate::MANUAL; t++) {
+ RequestTemplate reqTemplate = (RequestTemplate) t;
+ session->constructDefaultRequestSettings(
+ reqTemplate,
+ [&](auto status, const auto& req) {
+ ALOGI("constructDefaultRequestSettings returns status:%d", (int)status);
+ if (reqTemplate == RequestTemplate::ZERO_SHUTTER_LAG ||
+ reqTemplate == RequestTemplate::MANUAL) {
+ // optional templates
+ ASSERT_TRUE(status == Status::OK || status == Status::ILLEGAL_ARGUMENT);
+ } else {
+ ASSERT_EQ(Status::OK, status);
+ }
+
+ if (status == Status::OK) {
+ const camera_metadata_t* metadata =
+ (camera_metadata_t*) req.data();
+ size_t expectedSize = req.size();
+ ASSERT_EQ(0, validate_camera_metadata_structure(
+ metadata, &expectedSize));
+ size_t entryCount = get_camera_metadata_entry_count(metadata);
+ // TODO: we can do better than 0 here. Need to check how many required
+ // request keys we've defined for each template
+ ASSERT_GT(entryCount, 0u);
+ ALOGI("template %u metadata entry count is %zu", t, entryCount);
+ } else {
+ ASSERT_EQ(0u, req.size());
+ }
+ });
+ }
+ session->close();
+ }
+ }
+}
+
+TEST_F(CameraHidlTest, configureStreams) {
+ CameraHidlEnvironment* env = CameraHidlEnvironment::Instance();
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames();
+
+ for (const auto& name : cameraDeviceNames) {
+ if (getCameraDeviceVersion(name) == CAMERA_DEVICE_API_VERSION_3_2) {
+ ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_2;
+ ALOGI("configureStreams: Testing camera device %s", name.c_str());
+ env->mProvider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ device3_2 = device;
+ });
+
+ sp<EmptyDeviceCb> cb = new EmptyDeviceCb;
+ sp<ICameraDeviceSession> session;
+ device3_2->open(
+ cb,
+ [&](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ session = newSession;
+ });
+
+
+ session->close();
+ }
+ }
+}
+
+int main(int argc, char **argv) {
+ ::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/evs/1.0/default/EvsCamera.cpp b/evs/1.0/default/EvsCamera.cpp
index 32d4ed7..6715a2e 100644
--- a/evs/1.0/default/EvsCamera.cpp
+++ b/evs/1.0/default/EvsCamera.cpp
@@ -48,14 +48,14 @@
// Set up dummy data for testing
if (mDescription.cameraId == kCameraName_Backup) {
- mDescription.hints = UsageHint::USAGE_HINT_REVERSE;
+ mDescription.hints = static_cast<uint32_t>(UsageHint::USAGE_HINT_REVERSE);
mDescription.vendorFlags = 0xFFFFFFFF; // Arbitrary value
mDescription.defaultHorResolution = 320; // 1/2 NTSC/VGA
mDescription.defaultVerResolution = 240; // 1/2 NTSC/VGA
}
else if (mDescription.cameraId == kCameraName_RightTurn) {
// Nothing but the name and the usage hint
- mDescription.hints = UsageHint::USAGE_HINT_RIGHT_TURN;
+ mDescription.hints = static_cast<uint32_t>(UsageHint::USAGE_HINT_RIGHT_TURN);
}
else {
// Leave empty for a minimalist camera description without even a hint
@@ -149,7 +149,7 @@
return EvsResult::OK;
}
-Return<EvsResult> EvsCamera::doneWithFrame(uint32_t frameId, const hidl_handle& bufferHandle) {
+Return<EvsResult> EvsCamera::doneWithFrame(uint32_t /* frameId */, const hidl_handle& bufferHandle) {
ALOGD("doneWithFrame");
std::lock_guard<std::mutex> lock(mAccessLock);
diff --git a/evs/1.0/types.hal b/evs/1.0/types.hal
index e0051e1..fd9dcdc 100644
--- a/evs/1.0/types.hal
+++ b/evs/1.0/types.hal
@@ -32,7 +32,6 @@
USAGE_HINT_REVERSE = 0x00000001,
USAGE_HINT_LEFT_TURN = 0x00000002,
USAGE_HINT_RIGHT_TURN = 0x00000004,
- // remaining bits are reserved for future use
};
@@ -48,11 +47,11 @@
* should be set to ZERO.
*/
struct CameraDesc {
- string cameraId;
- UsageHint hints; // Bit flags (legal to | values together) (TODO: b/31702236)
- uint32_t vendorFlags; // Opaque value from driver
- uint32_t defaultHorResolution; // Units of pixels
- uint32_t defaultVerResolution; // Units of pixels
+ string cameraId;
+ bitfield<UsageHint> hints; // Mask of usage hints
+ uint32_t vendorFlags; // Opaque value from driver
+ uint32_t defaultHorResolution; // Units of pixels
+ uint32_t defaultVerResolution; // Units of pixels
};
@@ -90,7 +89,6 @@
/* Error codes used in EVS HAL interface. */
-/* TODO: Adopt a common set of function return codes */
enum EvsResult : uint32_t {
OK = 0,
INVALID_ARG,
diff --git a/graphics/Android.bp b/graphics/Android.bp
index 796ef41..6d55dd1 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -8,4 +8,5 @@
"composer/2.1/default",
"mapper/2.0",
"mapper/2.0/default",
+ "mapper/2.0/vts/functional",
]
diff --git a/graphics/Android.mk b/graphics/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/graphics/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/graphics/allocator/2.0/Android.mk b/graphics/allocator/2.0/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/graphics/allocator/2.0/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/graphics/allocator/2.0/vts/AllocatorClient.vts b/graphics/allocator/2.0/vts/AllocatorClient.vts
new file mode 100644
index 0000000..face060
--- /dev/null
+++ b/graphics/allocator/2.0/vts/AllocatorClient.vts
@@ -0,0 +1,169 @@
+component_class: HAL_HIDL
+component_type_version: 2.0
+component_name: "IAllocatorClient"
+
+package: "android.hardware.graphics.allocator"
+
+import: "android.hardware.graphics.allocator@2.0::types"
+import: "android.hardware.graphics.common@1.0::types"
+
+interface: {
+ attribute: {
+ name: "::android::hardware::graphics::allocator::V2_0::IAllocatorClient::BufferDescriptorInfo"
+ type: TYPE_STRUCT
+ struct_value: {
+ name: "width"
+ type: TYPE_SCALAR
+ scalar_type: "uint32_t"
+ }
+ struct_value: {
+ name: "height"
+ type: TYPE_SCALAR
+ scalar_type: "uint32_t"
+ }
+ struct_value: {
+ name: "layerCount"
+ type: TYPE_SCALAR
+ scalar_type: "uint32_t"
+ }
+ struct_value: {
+ name: "format"
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::common::V1_0::PixelFormat"
+ }
+ struct_value: {
+ name: "producerUsageMask"
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ struct_value: {
+ name: "consumerUsageMask"
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ }
+
+ api: {
+ name: "createDescriptor"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ arg: {
+ type: TYPE_STRUCT
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::IAllocatorClient::BufferDescriptorInfo"
+ }
+ callflow: {
+ entry: true
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+ api: {
+ name: "destroyDescriptor"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ arg: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ callflow: {
+ exit: true
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+ api: {
+ name: "testAllocate"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ arg: {
+ type: TYPE_VECTOR
+ vector_value: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ }
+ callflow: {
+ next: "allocate"
+ }
+ }
+
+ api: {
+ name: "allocate"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_VECTOR
+ vector_value: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ }
+ arg: {
+ type: TYPE_VECTOR
+ vector_value: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ }
+ callflow: {
+ next: "exportHandle"
+ }
+ }
+
+ api: {
+ name: "free"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ arg: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ callflow: {
+ exit: true
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+ api: {
+ name: "exportHandle"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_HANDLE
+ }
+ arg: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ arg: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ callflow: {
+ next: "free"
+ }
+ }
+
+}
diff --git a/graphics/allocator/2.0/vts/Android.mk b/graphics/allocator/2.0/vts/Android.mk
new file mode 100644
index 0000000..00fd344
--- /dev/null
+++ b/graphics/allocator/2.0/vts/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(LOCAL_PATH)/functional/vts/testcases/hal/graphics/allocator/hidl/target/Android.mk
diff --git a/graphics/allocator/2.0/vts/functional/Android.bp b/graphics/allocator/2.0/vts/functional/Android.bp
index e1966dc..194b228 100644
--- a/graphics/allocator/2.0/vts/functional/Android.bp
+++ b/graphics/allocator/2.0/vts/functional/Android.bp
@@ -31,7 +31,11 @@
],
static_libs: ["libgtest"],
cflags: [
+ "--coverage",
"-O0",
"-g",
],
+ ldflags: [
+ "--coverage",
+ ],
}
diff --git a/graphics/allocator/2.0/vts/functional/vts/testcases/hal/graphics/allocator/hidl/target/Android.mk b/graphics/allocator/2.0/vts/functional/vts/testcases/hal/graphics/allocator/hidl/target/Android.mk
new file mode 100644
index 0000000..2c1617f
--- /dev/null
+++ b/graphics/allocator/2.0/vts/functional/vts/testcases/hal/graphics/allocator/hidl/target/Android.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := HalGraphicsAllocatorHidlTargetTest
+VTS_CONFIG_SRC_DIR := testcases/hal/graphics/allocator/hidl/target
+include test/vts/tools/build/Android.host_config.mk
diff --git a/graphics/allocator/2.0/vts/functional/vts/testcases/hal/graphics/allocator/hidl/target/AndroidTest.xml b/graphics/allocator/2.0/vts/functional/vts/testcases/hal/graphics/allocator/hidl/target/AndroidTest.xml
new file mode 100644
index 0000000..4ef2e95
--- /dev/null
+++ b/graphics/allocator/2.0/vts/functional/vts/testcases/hal/graphics/allocator/hidl/target/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for VTS Graphics Allocator HIDL HAL's basic target-side test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HidlHalTest.push" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="HalGraphicsAllocatorHidlTargetTest" />
+ <option name="binary-test-sources" value="
+ _32bit::DATA/nativetest/graphics_allocator_hidl_hal_test/graphics_allocator_hidl_hal_test,
+ _64bit::DATA/nativetest64/graphics_allocator_hidl_hal_test/graphics_allocator_hidl_hal_test,
+ " />
+ <option name="binary-test-type" value="gtest" />
+ <option name="test-timeout" value="1m" />
+ </test>
+</configuration>
diff --git a/graphics/allocator/Android.mk b/graphics/allocator/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/graphics/allocator/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/graphics/mapper/2.0/Android.mk b/graphics/mapper/2.0/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/graphics/mapper/2.0/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/graphics/mapper/2.0/vts/Android.mk b/graphics/mapper/2.0/vts/Android.mk
new file mode 100644
index 0000000..6185ddc
--- /dev/null
+++ b/graphics/mapper/2.0/vts/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(LOCAL_PATH)/functional/vts/testcases/hal/graphics/mapper/hidl/target/Android.mk
diff --git a/graphics/mapper/2.0/vts/Mapper.vts b/graphics/mapper/2.0/vts/Mapper.vts
new file mode 100644
index 0000000..26e049f
--- /dev/null
+++ b/graphics/mapper/2.0/vts/Mapper.vts
@@ -0,0 +1,280 @@
+component_class: HAL_HIDL
+component_type_version: 2.0
+component_name: "IMapper"
+
+package: "android.hardware.graphics.mapper"
+
+import: "android.hardware.graphics.allocator@2.0::types"
+import: "android.hardware.graphics.common@1.0::types"
+import: "android.hardware.graphics.mapper@2.0::types"
+
+interface: {
+ attribute: {
+ name: "::android::hardware::graphics::mapper::V2_0::IMapper::Rect"
+ type: TYPE_STRUCT
+ struct_value: {
+ name: "left"
+ type: TYPE_SCALAR
+ scalar_type: "int32_t"
+ }
+ struct_value: {
+ name: "top"
+ type: TYPE_SCALAR
+ scalar_type: "int32_t"
+ }
+ struct_value: {
+ name: "width"
+ type: TYPE_SCALAR
+ scalar_type: "int32_t"
+ }
+ struct_value: {
+ name: "height"
+ type: TYPE_SCALAR
+ scalar_type: "int32_t"
+ }
+ }
+
+ api: {
+ name: "retain"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ entry: true
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+ api: {
+ name: "release"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ exit: true
+ }
+ }
+
+ api: {
+ name: "getDimensions"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_SCALAR
+ scalar_type: "uint32_t"
+ }
+ return_type_hidl: {
+ type: TYPE_SCALAR
+ scalar_type: "uint32_t"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+ api: {
+ name: "getFormat"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::common::V1_0::PixelFormat"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+ api: {
+ name: "getLayerCount"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_SCALAR
+ scalar_type: "uint32_t"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+ api: {
+ name: "getProducerUsageMask"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+ api: {
+ name: "getConsumerUsageMask"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+ api: {
+ name: "getBackingStore"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+ api: {
+ name: "getStride"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_SCALAR
+ scalar_type: "uint32_t"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+ api: {
+ name: "lock"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_POINTER
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ arg: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ arg: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ arg: {
+ type: TYPE_STRUCT
+ predefined_type: "::android::hardware::graphics::mapper::V2_0::IMapper::Rect"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ next: "unlock"
+ }
+ }
+
+ api: {
+ name: "lockFlex"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_STRUCT
+ predefined_type: "::android::hardware::graphics::mapper::V2_0::FlexLayout"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ arg: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ arg: {
+ type: TYPE_SCALAR
+ scalar_type: "uint64_t"
+ }
+ arg: {
+ type: TYPE_STRUCT
+ predefined_type: "::android::hardware::graphics::mapper::V2_0::IMapper::Rect"
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ next: "unlock"
+ }
+ }
+
+ api: {
+ name: "unlock"
+ return_type_hidl: {
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::allocator::V2_0::Error"
+ }
+ return_type_hidl: {
+ type: TYPE_HANDLE
+ }
+ arg: {
+ type: TYPE_HANDLE
+ }
+ callflow: {
+ next: "*"
+ }
+ }
+
+}
diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..53e6d16
--- /dev/null
+++ b/graphics/mapper/2.0/vts/functional/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "graphics_mapper_hidl_hal_test",
+ gtest: true,
+ srcs: ["graphics_mapper_hidl_hal_test.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libnativehelper",
+ "libsync",
+ "libutils",
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.mapper@2.0",
+ ],
+ static_libs: ["libgtest"],
+ cflags: [
+ "--coverage",
+ "-O0",
+ "-g",
+ ],
+ ldflags: [
+ "--coverage",
+ ],
+}
diff --git a/graphics/mapper/2.0/vts/functional/graphics_mapper_hidl_hal_test.cpp b/graphics/mapper/2.0/vts/functional/graphics_mapper_hidl_hal_test.cpp
new file mode 100644
index 0000000..840da1a
--- /dev/null
+++ b/graphics/mapper/2.0/vts/functional/graphics_mapper_hidl_hal_test.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "graphics_mapper_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <gtest/gtest.h>
+#include <sync/sync.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace tests {
+namespace {
+
+using namespace android::hardware::graphics::allocator::V2_0;
+using namespace android::hardware::graphics::common::V1_0;
+
+class GraphicsMapperHidlTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ mAllocator = IAllocator::getService("gralloc");
+ ASSERT_NE(mAllocator, nullptr);
+
+ mAllocator->createClient([this](const auto& error, const auto& client) {
+ if (error == Error::NONE) {
+ mAllocatorClient = client;
+ }
+ });
+ ASSERT_NE(mAllocatorClient, nullptr);
+
+ mMapper = IMapper::getService("gralloc-mapper");
+ ASSERT_NE(nullptr, mMapper.get());
+ ASSERT_FALSE(mMapper->isRemote());
+
+ mDummyDescriptorInfo.width = 64;
+ mDummyDescriptorInfo.height = 64;
+ mDummyDescriptorInfo.layerCount = 1;
+ mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
+ mDummyDescriptorInfo.producerUsageMask =
+ static_cast<uint64_t>(ProducerUsage::CPU_WRITE);
+ mDummyDescriptorInfo.consumerUsageMask =
+ static_cast<uint64_t>(ConsumerUsage::CPU_READ);
+ }
+
+ void TearDown() override {}
+
+ const native_handle_t* allocate(
+ const IAllocatorClient::BufferDescriptorInfo& info) {
+ // create descriptor
+ Error err = Error::NO_RESOURCES;
+ BufferDescriptor descriptor;
+ mAllocatorClient->createDescriptor(
+ info, [&](const auto& tmpError, const auto& tmpDescriptor) {
+ err = tmpError;
+ descriptor = tmpDescriptor;
+ });
+ if (err != Error::NONE) {
+ return nullptr;
+ }
+
+ // allocate buffer
+ hidl_vec<BufferDescriptor> descriptors;
+ hidl_vec<Buffer> buffers;
+ descriptors.setToExternal(&descriptor, 1);
+ err = Error::NO_RESOURCES;
+ mAllocatorClient->allocate(
+ descriptors, [&](const auto& tmpError, const auto& tmpBuffers) {
+ err = tmpError;
+ buffers = tmpBuffers;
+ });
+ if ((err != Error::NONE && err != Error::NOT_SHARED) ||
+ buffers.size() != 1) {
+ mAllocatorClient->destroyDescriptor(descriptors[0]);
+ return nullptr;
+ }
+
+ // export handle
+ err = Error::NO_RESOURCES;
+ const native_handle_t* handle = nullptr;
+ mAllocatorClient->exportHandle(
+ descriptors[0], buffers[0],
+ [&](const auto& tmpError, const auto& tmpHandle) {
+ err = tmpError;
+ if (err != Error::NONE) {
+ return;
+ }
+
+ handle = native_handle_clone(tmpHandle);
+ if (!handle) {
+ err = Error::NO_RESOURCES;
+ return;
+ }
+
+ err = mMapper->retain(handle);
+ if (err != Error::NONE) {
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle_t*>(handle));
+ handle = nullptr;
+ }
+ });
+
+ mAllocatorClient->destroyDescriptor(descriptors[0]);
+ mAllocatorClient->free(buffers[0]);
+
+ if (err != Error::NONE) {
+ return nullptr;
+ }
+
+ return handle;
+ }
+
+ sp<IMapper> mMapper;
+
+ IAllocatorClient::BufferDescriptorInfo mDummyDescriptorInfo{};
+
+ private:
+ sp<IAllocator> mAllocator;
+ sp<IAllocatorClient> mAllocatorClient;
+};
+
+/**
+ * Test IMapper::retain and IMapper::release.
+ */
+TEST_F(GraphicsMapperHidlTest, RetainRelease) {
+ const native_handle_t* buffer = allocate(mDummyDescriptorInfo);
+ ASSERT_NE(buffer, nullptr);
+
+ const int maxRefs = 10;
+ for (int i = 0; i < maxRefs; i++) {
+ auto err = mMapper->retain(buffer);
+ EXPECT_EQ(Error::NONE, err);
+ }
+ for (int i = 0; i < maxRefs; i++) {
+ auto err = mMapper->release(buffer);
+ EXPECT_EQ(Error::NONE, err);
+ }
+
+ auto err = mMapper->release(buffer);
+ EXPECT_EQ(Error::NONE, err);
+}
+
+/**
+ * Test IMapper::get* getters.
+ */
+TEST_F(GraphicsMapperHidlTest, Getters) {
+ const native_handle_t* buffer = allocate(mDummyDescriptorInfo);
+ ASSERT_NE(buffer, nullptr);
+
+ Error err = Error::NO_RESOURCES;
+ IAllocatorClient::BufferDescriptorInfo info{};
+ mMapper->getDimensions(buffer, [&](const auto& tmpError, const auto& tmpWidth,
+ const auto& tmpHeight) {
+ err = tmpError;
+ info.width = tmpWidth;
+ info.height = tmpHeight;
+ });
+ EXPECT_EQ(Error::NONE, err);
+ mMapper->getFormat(buffer, [&](const auto& tmpError, const auto& tmpFormat) {
+ err = tmpError;
+ info.format = tmpFormat;
+ });
+ EXPECT_EQ(Error::NONE, err);
+ mMapper->getProducerUsageMask(
+ buffer, [&](const auto& tmpError, const auto& tmpUsage) {
+ err = tmpError;
+ info.producerUsageMask = tmpUsage;
+ });
+ EXPECT_EQ(Error::NONE, err);
+ mMapper->getConsumerUsageMask(
+ buffer, [&](const auto& tmpError, const auto& tmpUsage) {
+ err = tmpError;
+ info.consumerUsageMask = tmpUsage;
+ });
+ EXPECT_EQ(Error::NONE, err);
+
+ EXPECT_EQ(mDummyDescriptorInfo.width, info.width);
+ EXPECT_EQ(mDummyDescriptorInfo.height, info.height);
+ EXPECT_EQ(mDummyDescriptorInfo.format, info.format);
+ EXPECT_EQ(mDummyDescriptorInfo.producerUsageMask, info.producerUsageMask);
+ EXPECT_EQ(mDummyDescriptorInfo.consumerUsageMask, info.consumerUsageMask);
+
+ BackingStore store = 0;
+ mMapper->getBackingStore(buffer,
+ [&](const auto& tmpError, const auto& tmpStore) {
+ err = tmpError;
+ store = tmpStore;
+ });
+ EXPECT_EQ(Error::NONE, err);
+
+ uint32_t stride = 0;
+ mMapper->getStride(buffer, [&](const auto& tmpError, const auto& tmpStride) {
+ err = tmpError;
+ stride = tmpStride;
+ });
+ EXPECT_EQ(Error::NONE, err);
+ EXPECT_LE(info.width, stride);
+
+ err = mMapper->release(buffer);
+ EXPECT_EQ(Error::NONE, err);
+}
+
+/**
+ * Test IMapper::lock and IMapper::unlock.
+ */
+TEST_F(GraphicsMapperHidlTest, LockBasic) {
+ const auto& info = mDummyDescriptorInfo;
+ const native_handle_t* buffer = allocate(info);
+ ASSERT_NE(buffer, nullptr);
+
+ Error err = Error::NO_RESOURCES;
+ uint32_t stride = 0;
+ mMapper->getStride(buffer, [&](const auto& tmpError, const auto& tmpStride) {
+ err = tmpError;
+ stride = tmpStride;
+ });
+ EXPECT_EQ(Error::NONE, err);
+
+ // lock buffer for writing
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ hidl_handle acquireFence(nullptr);
+ uint32_t* data;
+ err = Error::NO_RESOURCES;
+ mMapper->lock(buffer, info.producerUsageMask, 0, region, acquireFence,
+ [&](const auto& tmpError, const auto& tmpData) {
+ err = tmpError;
+ data = static_cast<uint32_t*>(tmpData);
+ });
+
+ if (err == Error::NONE) {
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ data[stride * y + x] = info.height * y + x;
+ }
+ }
+ } else {
+ EXPECT_EQ(Error::NONE, err);
+ }
+
+ err = Error::NO_RESOURCES;
+ mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ err = tmpError;
+ auto handle = tmpReleaseFence.getNativeHandle();
+ if (handle && handle->numFds == 1) {
+ sync_wait(handle->data[0], -1);
+ close(handle->data[0]);
+ }
+ });
+ EXPECT_EQ(Error::NONE, err);
+
+ // lock buffer for reading
+ mMapper->lock(buffer, 0, info.consumerUsageMask, region, acquireFence,
+ [&](const auto& tmpError, const auto& tmpData) {
+ err = tmpError;
+ data = static_cast<uint32_t*>(tmpData);
+ });
+ if (err == Error::NONE) {
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ EXPECT_EQ(info.height * y + x, data[stride * y + x]);
+ }
+ }
+ } else {
+ EXPECT_EQ(Error::NONE, err);
+ }
+
+ err = Error::NO_RESOURCES;
+ mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ err = tmpError;
+ auto handle = tmpReleaseFence.getNativeHandle();
+ if (handle && handle->numFds == 1) {
+ sync_wait(handle->data[0], -1);
+ close(handle->data[0]);
+ }
+ });
+ EXPECT_EQ(Error::NONE, err);
+
+ err = mMapper->release(buffer);
+ EXPECT_EQ(Error::NONE, err);
+}
+
+} // namespace anonymous
+} // namespace tests
+} // namespace V2_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+
+ return status;
+}
diff --git a/graphics/mapper/2.0/vts/functional/vts/testcases/hal/graphics/mapper/hidl/target/Android.mk b/graphics/mapper/2.0/vts/functional/vts/testcases/hal/graphics/mapper/hidl/target/Android.mk
new file mode 100644
index 0000000..5f7fae8
--- /dev/null
+++ b/graphics/mapper/2.0/vts/functional/vts/testcases/hal/graphics/mapper/hidl/target/Android.mk
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := HalGraphicsMapperHidlTargetTest
+VTS_CONFIG_SRC_DIR := testcases/hal/graphics/mapper/hidl/target
+include test/vts/tools/build/Android.host_config.mk
diff --git a/graphics/mapper/2.0/vts/functional/vts/testcases/hal/graphics/mapper/hidl/target/AndroidTest.xml b/graphics/mapper/2.0/vts/functional/vts/testcases/hal/graphics/mapper/hidl/target/AndroidTest.xml
new file mode 100644
index 0000000..b602ec4
--- /dev/null
+++ b/graphics/mapper/2.0/vts/functional/vts/testcases/hal/graphics/mapper/hidl/target/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for VTS Graphics Mapper HIDL HAL's basic target-side test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="push-group" value="HidlHalTest.push" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.VtsPythonVirtualenvPreparer" />
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="HalGraphicsMapperHidlTargetTest" />
+ <option name="binary-test-sources" value="
+ _32bit::DATA/nativetest/graphics_mapper_hidl_hal_test/graphics_mapper_hidl_hal_test,
+ _64bit::DATA/nativetest64/graphics_mapper_hidl_hal_test/graphics_mapper_hidl_hal_test,
+ " />
+ <option name="binary-test-type" value="gtest" />
+ <option name="test-timeout" value="1m" />
+ </test>
+</configuration>
diff --git a/graphics/mapper/2.0/vts/types.vts b/graphics/mapper/2.0/vts/types.vts
new file mode 100644
index 0000000..fee8535
--- /dev/null
+++ b/graphics/mapper/2.0/vts/types.vts
@@ -0,0 +1,139 @@
+component_class: HAL_HIDL
+component_type_version: 2.0
+component_name: "types"
+
+package: "android.hardware.graphics.mapper"
+
+
+attribute: {
+ name: "::android::hardware::graphics::mapper::V2_0::FlexComponent"
+ type: TYPE_ENUM
+ enum_value: {
+ scalar_type: "int32_t"
+
+ enumerator: "Y"
+ scalar_value: {
+ int32_t: 1
+ }
+ enumerator: "CB"
+ scalar_value: {
+ int32_t: 2
+ }
+ enumerator: "CR"
+ scalar_value: {
+ int32_t: 4
+ }
+ enumerator: "R"
+ scalar_value: {
+ int32_t: 1024
+ }
+ enumerator: "G"
+ scalar_value: {
+ int32_t: 2048
+ }
+ enumerator: "B"
+ scalar_value: {
+ int32_t: 4096
+ }
+ enumerator: "A"
+ scalar_value: {
+ int32_t: 1073741824
+ }
+ }
+}
+
+attribute: {
+ name: "::android::hardware::graphics::mapper::V2_0::FlexFormat"
+ type: TYPE_ENUM
+ enum_value: {
+ scalar_type: "int32_t"
+
+ enumerator: "INVALID"
+ scalar_value: {
+ int32_t: 0
+ }
+ enumerator: "Y"
+ scalar_value: {
+ int32_t: 1
+ }
+ enumerator: "YCBCR"
+ scalar_value: {
+ int32_t: 7
+ }
+ enumerator: "YCBCRA"
+ scalar_value: {
+ int32_t: 1073741831
+ }
+ enumerator: "RGB"
+ scalar_value: {
+ int32_t: 7168
+ }
+ enumerator: "RGBA"
+ scalar_value: {
+ int32_t: 1073748992
+ }
+ }
+}
+
+attribute: {
+ name: "::android::hardware::graphics::mapper::V2_0::FlexPlane"
+ type: TYPE_STRUCT
+ struct_value: {
+ name: "topLeft"
+ type: TYPE_POINTER
+ }
+ struct_value: {
+ name: "component"
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::mapper::V2_0::FlexComponent"
+ }
+ struct_value: {
+ name: "bitsPerComponent"
+ type: TYPE_SCALAR
+ scalar_type: "int32_t"
+ }
+ struct_value: {
+ name: "bitsUsed"
+ type: TYPE_SCALAR
+ scalar_type: "int32_t"
+ }
+ struct_value: {
+ name: "hIncrement"
+ type: TYPE_SCALAR
+ scalar_type: "int32_t"
+ }
+ struct_value: {
+ name: "vIncrement"
+ type: TYPE_SCALAR
+ scalar_type: "int32_t"
+ }
+ struct_value: {
+ name: "hSubsampling"
+ type: TYPE_SCALAR
+ scalar_type: "int32_t"
+ }
+ struct_value: {
+ name: "vSubsampling"
+ type: TYPE_SCALAR
+ scalar_type: "int32_t"
+ }
+}
+
+attribute: {
+ name: "::android::hardware::graphics::mapper::V2_0::FlexLayout"
+ type: TYPE_STRUCT
+ struct_value: {
+ name: "format"
+ type: TYPE_ENUM
+ predefined_type: "::android::hardware::graphics::mapper::V2_0::FlexFormat"
+ }
+ struct_value: {
+ name: "planes"
+ type: TYPE_VECTOR
+ vector_value: {
+ type: TYPE_STRUCT
+ predefined_type: "::android::hardware::graphics::mapper::V2_0::FlexPlane"
+ }
+ }
+}
+
diff --git a/graphics/mapper/Android.mk b/graphics/mapper/Android.mk
new file mode 100644
index 0000000..f9e3276
--- /dev/null
+++ b/graphics/mapper/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-subdir-makefiles)
diff --git a/soundtrigger/2.0/vts/functional/vts/testcases/hal/soundtrigger/hidl/target/AndroidTest.xml b/soundtrigger/2.0/vts/functional/vts/testcases/hal/soundtrigger/hidl/target/AndroidTest.xml
index b75d97e..ca8ecdb 100644
--- a/soundtrigger/2.0/vts/functional/vts/testcases/hal/soundtrigger/hidl/target/AndroidTest.xml
+++ b/soundtrigger/2.0/vts/functional/vts/testcases/hal/soundtrigger/hidl/target/AndroidTest.xml
@@ -24,6 +24,7 @@
_32bit::DATA/nativetest/soundtrigger_hidl_hal_test/soundtrigger_hidl_hal_test,
_64bit::DATA/nativetest64/soundtrigger_hidl_hal_test/soundtrigger_hidl_hal_test,
"/>
+ <option name="test-config-path" value="vts/testcases/hal/soundtrigger/hidl/target/HalSoundTriggerHidlTargetBasicTest.config" />
<option name="binary-test-type" value="gtest" />
<option name="test-timeout" value="1m" />
</test>
diff --git a/soundtrigger/2.0/vts/functional/vts/testcases/hal/soundtrigger/hidl/target/HalSoundTriggerHidlTargetBasicTest.config b/soundtrigger/2.0/vts/functional/vts/testcases/hal/soundtrigger/hidl/target/HalSoundTriggerHidlTargetBasicTest.config
new file mode 100644
index 0000000..241ec14
--- /dev/null
+++ b/soundtrigger/2.0/vts/functional/vts/testcases/hal/soundtrigger/hidl/target/HalSoundTriggerHidlTargetBasicTest.config
@@ -0,0 +1,41 @@
+{
+ "use_gae_db": true,
+ "coverage": true,
+ "modules": [
+ {
+ "module_name": "system/lib64/hw/sound_trigger.primary.bullhead",
+ "git_project": {
+ "name": "platform/vendor/lge/bullhead",
+ "path": "vendor/lge/bullhead"
+ },
+ },
+ {
+ "module_name": "system/lib64/hw/sound_trigger.primary.angler",
+ "git_project": {
+ "name": "platform/vendor/huawei/angler",
+ "path": "vendor/huawei/angler"
+ },
+ },
+ {
+ "module_name": "system/lib64/hw/sound_trigger.primary.marlin",
+ "git_project": {
+ "name": "platform/vendor/google_devices/marlin",
+ "path": "vendor/google_devices/marlin"
+ },
+ },
+ {
+ "module_name": "system/lib64/hw/sound_trigger.primary.sailfish",
+ "git_project": {
+ "name": "platform/vendor/google_devices/marlin",
+ "path": "vendor/google_devices/marlin"
+ },
+ },
+ {
+ "module_name": "system/lib64/hw/android.hardware.soundtrigger@2.0-impl",
+ "git_project": {
+ "name": "platform/hardware/interfaces",
+ "path": "hardware/interfaces"
+ },
+ },
+ ]
+}
diff --git a/tv/cec/1.0/vts/functional/vts/testcases/hal/tv_cec/hidl/host/TvCecHidlTest.py b/tv/cec/1.0/vts/functional/vts/testcases/hal/tv_cec/hidl/host/TvCecHidlTest.py
index dcf21c9..80140c7 100644
--- a/tv/cec/1.0/vts/functional/vts/testcases/hal/tv_cec/hidl/host/TvCecHidlTest.py
+++ b/tv/cec/1.0/vts/functional/vts/testcases/hal/tv_cec/hidl/host/TvCecHidlTest.py
@@ -43,7 +43,7 @@
target_version=1.0,
target_package="android.hardware.tv.cec",
target_component_name="IHdmiCec",
- hw_binder_service_name="tv.cec",
+ hw_binder_service_name="cec-hal-1-0",
bits=64 if self.dut.is64Bit else 32)
def testGetCecVersion1(self):
diff --git a/tv/input/1.0/Android.bp b/tv/input/1.0/Android.bp
index 94dcdc9..9504961 100644
--- a/tv/input/1.0/Android.bp
+++ b/tv/input/1.0/Android.bp
@@ -128,3 +128,95 @@
"android.hidl.base@1.0",
],
}
+
+genrule {
+ name: "android.hardware.tv.input@1.0-ITvInput-vts.profiler_genc++",
+ tools: ["hidl-gen", "vtsc"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lvts -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.input@1.0 && $(location vtsc) -mPROFILER -tSOURCE -b$(genDir) android/hardware/tv/input/1.0/ $(genDir)/android/hardware/tv/input/1.0/",
+ srcs: [
+ "ITvInput.hal",
+ "types.hal",
+ ],
+ out: [
+ "android/hardware/tv/input/1.0/TvInput.vts.cpp",
+ "android/hardware/tv/input/1.0/types.vts.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.tv.input@1.0-ITvInput-vts.profiler_genc++_headers",
+ tools: ["hidl-gen", "vtsc"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lvts -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.input@1.0 && $(location vtsc) -mPROFILER -tHEADER -b$(genDir) android/hardware/tv/input/1.0/ $(genDir)/android/hardware/tv/input/1.0/",
+ srcs: [
+ "ITvInput.hal",
+ "types.hal",
+ ],
+ out: [
+ "android/hardware/tv/input/1.0/TvInput.vts.h",
+ "android/hardware/tv/input/1.0/types.vts.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.tv.input@1.0-ITvInput-vts.profiler",
+ generated_sources: ["android.hardware.tv.input@1.0-ITvInput-vts.profiler_genc++"],
+ generated_headers: ["android.hardware.tv.input@1.0-ITvInput-vts.profiler_genc++_headers"],
+ export_generated_headers: ["android.hardware.tv.input@1.0-ITvInput-vts.profiler_genc++_headers"],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "libvts_profiling",
+ "libvts_multidevice_proto",
+ "libprotobuf-cpp-full",
+ "android.hardware.audio.common@2.0",
+ "android.hidl.base@1.0",
+ "android.hardware.tv.input@1.0",
+ ],
+}
+
+genrule {
+ name: "android.hardware.tv.input@1.0-ITvInputCallback-vts.profiler_genc++",
+ tools: ["hidl-gen", "vtsc"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lvts -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.input@1.0 && $(location vtsc) -mPROFILER -tSOURCE -b$(genDir) android/hardware/tv/input/1.0/ $(genDir)/android/hardware/tv/input/1.0/",
+ srcs: [
+ "ITvInputCallback.hal",
+ "types.hal",
+ ],
+ out: [
+ "android/hardware/tv/input/1.0/TvInputCallback.vts.cpp",
+ "android/hardware/tv/input/1.0/types.vts.cpp",
+ ],
+}
+
+genrule {
+ name: "android.hardware.tv.input@1.0-ITvInputCallback-vts.profiler_genc++_headers",
+ tools: ["hidl-gen", "vtsc"],
+ cmd: "$(location hidl-gen) -o $(genDir) -Lvts -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.tv.input@1.0 && $(location vtsc) -mPROFILER -tHEADER -b$(genDir) android/hardware/tv/input/1.0/ $(genDir)/android/hardware/tv/input/1.0/",
+ srcs: [
+ "ITvInputCallback.hal",
+ "types.hal",
+ ],
+ out: [
+ "android/hardware/tv/input/1.0/TvInputCallback.vts.h",
+ "android/hardware/tv/input/1.0/types.vts.h",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.tv.input@1.0-ITvInputCallback-vts.profiler",
+ generated_sources: ["android.hardware.tv.input@1.0-ITvInputCallback-vts.profiler_genc++"],
+ generated_headers: ["android.hardware.tv.input@1.0-ITvInputCallback-vts.profiler_genc++_headers"],
+ export_generated_headers: ["android.hardware.tv.input@1.0-ITvInputCallback-vts.profiler_genc++_headers"],
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "libvts_profiling",
+ "libvts_multidevice_proto",
+ "libprotobuf-cpp-full",
+ "android.hardware.audio.common@2.0",
+ "android.hidl.base@1.0",
+ "android.hardware.tv.input@1.0",
+ ],
+}
diff --git a/tv/input/1.0/vts/functional/vts/testcases/hal/tv_input/hidl/host/TvInputHidlTest.py b/tv/input/1.0/vts/functional/vts/testcases/hal/tv_input/hidl/host/TvInputHidlTest.py
index c99c82c..9b49078 100644
--- a/tv/input/1.0/vts/functional/vts/testcases/hal/tv_input/hidl/host/TvInputHidlTest.py
+++ b/tv/input/1.0/vts/functional/vts/testcases/hal/tv_input/hidl/host/TvInputHidlTest.py
@@ -39,13 +39,14 @@
target_version=1.0,
target_package="android.hardware.tv.input",
target_component_name="ITvInput",
- bits=64)
+ hw_binder_service_name="tv-input-1-0",
+ bits=64 if self.dut.is64Bit else 32)
self.dut.shell.InvokeTerminal("one")
def testGetStreamConfigurations(self):
configs = self.dut.hal.tv_input.getStreamConfigurations(0)
- logging.info('tv input configs: %s', configs)
+ logging.info('return value of getStreamConfigurations(0): %s', configs)
if __name__ == "__main__":