Merge "Camera: Close acquire fences on failed buffers" into oc-dev
diff --git a/media/libaaudio/src/binding/AAudioBinderClient.h b/media/libaaudio/src/binding/AAudioBinderClient.h
index f7f2808..ca2da29 100644
--- a/media/libaaudio/src/binding/AAudioBinderClient.h
+++ b/media/libaaudio/src/binding/AAudioBinderClient.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAUDIO_AAUDIO_BINDER_CLIENT_H
-#define AAUDIO_AAUDIO_BINDER_CLIENT_H
+#ifndef ANDROID_AAUDIO_AAUDIO_BINDER_CLIENT_H
+#define ANDROID_AAUDIO_AAUDIO_BINDER_CLIENT_H
#include <aaudio/AAudio.h>
#include "AAudioServiceDefinitions.h"
@@ -91,4 +91,4 @@
} /* namespace aaudio */
-#endif //AAUDIO_AAUDIO_BINDER_CLIENT_H
+#endif //ANDROID_AAUDIO_AAUDIO_BINDER_CLIENT_H
diff --git a/media/libaaudio/src/binding/AAudioServiceInterface.h b/media/libaaudio/src/binding/AAudioServiceInterface.h
index b565499..824e5bc 100644
--- a/media/libaaudio/src/binding/AAudioServiceInterface.h
+++ b/media/libaaudio/src/binding/AAudioServiceInterface.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
-#define AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
+#ifndef ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
+#define ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
#include "binding/AAudioServiceDefinitions.h"
#include "binding/AAudioStreamRequest.h"
@@ -87,4 +87,4 @@
} /* namespace aaudio */
-#endif //AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
+#endif //ANDROID_AAUDIO_BINDING_AAUDIO_SERVICE_INTERFACE_H
diff --git a/media/libaaudio/src/binding/AAudioServiceMessage.h b/media/libaaudio/src/binding/AAudioServiceMessage.h
index d75aa32..b4377fb 100644
--- a/media/libaaudio/src/binding/AAudioServiceMessage.h
+++ b/media/libaaudio/src/binding/AAudioServiceMessage.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAUDIO_AAUDIO_SERVICE_MESSAGE_H
-#define AAUDIO_AAUDIO_SERVICE_MESSAGE_H
+#ifndef ANDROID_AAUDIO_AAUDIO_SERVICE_MESSAGE_H
+#define ANDROID_AAUDIO_AAUDIO_SERVICE_MESSAGE_H
#include <stdint.h>
@@ -64,4 +64,4 @@
} /* namespace aaudio */
-#endif //AAUDIO_AAUDIO_SERVICE_MESSAGE_H
+#endif //ANDROID_AAUDIO_AAUDIO_SERVICE_MESSAGE_H
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.h b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
index 78c4983..b1e4a7d 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.h
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BINDING_AAUDIO_STREAM_CONFIGURATION_H
-#define BINDING_AAUDIO_STREAM_CONFIGURATION_H
+#ifndef ANDROID_BINDING_AAUDIO_STREAM_CONFIGURATION_H
+#define ANDROID_BINDING_AAUDIO_STREAM_CONFIGURATION_H
#include <stdint.h>
@@ -101,4 +101,4 @@
} /* namespace aaudio */
-#endif //BINDING_AAUDIO_STREAM_CONFIGURATION_H
+#endif //ANDROID_BINDING_AAUDIO_STREAM_CONFIGURATION_H
diff --git a/media/libaaudio/src/binding/AAudioStreamRequest.h b/media/libaaudio/src/binding/AAudioStreamRequest.h
index d4bfbe1..77138da 100644
--- a/media/libaaudio/src/binding/AAudioStreamRequest.h
+++ b/media/libaaudio/src/binding/AAudioStreamRequest.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BINDING_AAUDIO_STREAM_REQUEST_H
-#define BINDING_AAUDIO_STREAM_REQUEST_H
+#ifndef ANDROID_BINDING_AAUDIO_STREAM_REQUEST_H
+#define ANDROID_BINDING_AAUDIO_STREAM_REQUEST_H
#include <stdint.h>
@@ -95,4 +95,4 @@
} /* namespace aaudio */
-#endif //BINDING_AAUDIO_STREAM_REQUEST_H
+#endif //ANDROID_BINDING_AAUDIO_STREAM_REQUEST_H
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h
index 4a1cb72..993075c 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.h
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BINDING_AUDIOENDPOINTPARCELABLE_H
-#define BINDING_AUDIOENDPOINTPARCELABLE_H
+#ifndef ANDROID_BINDING_AUDIO_ENDPOINT_PARCELABLE_H
+#define ANDROID_BINDING_AUDIO_ENDPOINT_PARCELABLE_H
#include <stdint.h>
@@ -75,4 +75,4 @@
} /* namespace aaudio */
-#endif //BINDING_AUDIOENDPOINTPARCELABLE_H
+#endif //ANDROID_BINDING_AUDIO_ENDPOINT_PARCELABLE_H
diff --git a/media/libaaudio/src/binding/IAAudioService.h b/media/libaaudio/src/binding/IAAudioService.h
index 2cee651..44a5e12 100644
--- a/media/libaaudio/src/binding/IAAudioService.h
+++ b/media/libaaudio/src/binding/IAAudioService.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BINDING_IAAUDIOSERVICE_H
-#define BINDING_IAAUDIOSERVICE_H
+#ifndef ANDROID_AAUDIO_IAAUDIO_SERVICE_H
+#define ANDROID_AAUDIO_IAAUDIO_SERVICE_H
#include <stdint.h>
#include <utils/RefBase.h>
@@ -103,4 +103,4 @@
} /* namespace android */
-#endif //BINDING_IAAUDIOSERVICE_H
+#endif //ANDROID_AAUDIO_IAAUDIO_SERVICE_H
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.cpp b/media/libaaudio/src/binding/RingBufferParcelable.cpp
index 05451f9..6b74b21 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.cpp
+++ b/media/libaaudio/src/binding/RingBufferParcelable.cpp
@@ -79,29 +79,49 @@
* The read and write must be symmetric.
*/
status_t RingBufferParcelable::writeToParcel(Parcel* parcel) const {
- parcel->writeInt32(mCapacityInFrames);
+ status_t status = parcel->writeInt32(mCapacityInFrames);
+ if (status != NO_ERROR) goto error;
if (mCapacityInFrames > 0) {
- parcel->writeInt32(mBytesPerFrame);
- parcel->writeInt32(mFramesPerBurst);
- parcel->writeInt32(mFlags);
- mReadCounterParcelable.writeToParcel(parcel);
- mWriteCounterParcelable.writeToParcel(parcel);
- mDataParcelable.writeToParcel(parcel);
+ status = parcel->writeInt32(mBytesPerFrame);
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32(mFramesPerBurst);
+ if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32(mFlags);
+ if (status != NO_ERROR) goto error;
+ status = mReadCounterParcelable.writeToParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ status = mWriteCounterParcelable.writeToParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ status = mDataParcelable.writeToParcel(parcel);
+ if (status != NO_ERROR) goto error;
}
- return NO_ERROR; // TODO check for errors above
+ return NO_ERROR;
+error:
+ ALOGE("RingBufferParcelable::writeToParcel() error = %d", status);
+ return status;
}
status_t RingBufferParcelable::readFromParcel(const Parcel* parcel) {
- parcel->readInt32(&mCapacityInFrames);
+ status_t status = parcel->readInt32(&mCapacityInFrames);
+ if (status != NO_ERROR) goto error;
if (mCapacityInFrames > 0) {
- parcel->readInt32(&mBytesPerFrame);
- parcel->readInt32(&mFramesPerBurst);
- parcel->readInt32((int32_t *)&mFlags);
- mReadCounterParcelable.readFromParcel(parcel);
- mWriteCounterParcelable.readFromParcel(parcel);
- mDataParcelable.readFromParcel(parcel);
+ status = parcel->readInt32(&mBytesPerFrame);
+ if (status != NO_ERROR) goto error;
+ status = parcel->readInt32(&mFramesPerBurst);
+ if (status != NO_ERROR) goto error;
+ status = parcel->readInt32((int32_t *)&mFlags);
+ if (status != NO_ERROR) goto error;
+ status = mReadCounterParcelable.readFromParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ status = mWriteCounterParcelable.readFromParcel(parcel);
+ if (status != NO_ERROR) goto error;
+ status = mDataParcelable.readFromParcel(parcel);
+ if (status != NO_ERROR) goto error;
}
- return NO_ERROR; // TODO check for errors above
+ return NO_ERROR;
+error:
+ ALOGE("RingBufferParcelable::readFromParcel() error = %d", status);
+ return status;
}
aaudio_result_t RingBufferParcelable::resolve(SharedMemoryParcelable *memoryParcels, RingBufferDescriptor *descriptor) {
@@ -141,7 +161,7 @@
ALOGE("RingBufferParcelable invalid mBytesPerFrame = %d", mBytesPerFrame);
return AAUDIO_ERROR_INTERNAL;
}
- if (mFramesPerBurst < 0 || mFramesPerBurst >= 1024) {
+ if (mFramesPerBurst < 0 || mFramesPerBurst >= 16 * 1024) {
ALOGE("RingBufferParcelable invalid mFramesPerBurst = %d", mFramesPerBurst);
return AAUDIO_ERROR_INTERNAL;
}
diff --git a/media/libaaudio/src/binding/RingBufferParcelable.h b/media/libaaudio/src/binding/RingBufferParcelable.h
index 5fc5d00..bd562f2 100644
--- a/media/libaaudio/src/binding/RingBufferParcelable.h
+++ b/media/libaaudio/src/binding/RingBufferParcelable.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BINDING_RINGBUFFER_PARCELABLE_H
-#define BINDING_RINGBUFFER_PARCELABLE_H
+#ifndef ANDROID_AAUDIO_RINGBUFFER_PARCELABLE_H
+#define ANDROID_AAUDIO_RINGBUFFER_PARCELABLE_H
#include <stdint.h>
@@ -82,4 +82,4 @@
} /* namespace aaudio */
-#endif //BINDING_RINGBUFFER_PARCELABLE_H
+#endif //ANDROID_AAUDIO_RINGBUFFER_PARCELABLE_H
diff --git a/media/libaaudio/src/binding/SharedMemoryParcelable.h b/media/libaaudio/src/binding/SharedMemoryParcelable.h
index 64fb473..4b94b46 100644
--- a/media/libaaudio/src/binding/SharedMemoryParcelable.h
+++ b/media/libaaudio/src/binding/SharedMemoryParcelable.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BINDING_SHAREDMEMORYPARCELABLE_H
-#define BINDING_SHAREDMEMORYPARCELABLE_H
+#ifndef ANDROID_AAUDIO_SHARED_MEMORY_PARCELABLE_H
+#define ANDROID_AAUDIO_SHARED_MEMORY_PARCELABLE_H
#include <stdint.h>
@@ -75,4 +75,4 @@
} /* namespace aaudio */
-#endif //BINDING_SHAREDMEMORYPARCELABLE_H
+#endif //ANDROID_AAUDIO_SHARED_MEMORY_PARCELABLE_H
diff --git a/media/libaaudio/src/binding/SharedRegionParcelable.h b/media/libaaudio/src/binding/SharedRegionParcelable.h
index e9f5785..f6babfd 100644
--- a/media/libaaudio/src/binding/SharedRegionParcelable.h
+++ b/media/libaaudio/src/binding/SharedRegionParcelable.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef BINDING_SHAREDREGIONPARCELABLE_H
-#define BINDING_SHAREDREGIONPARCELABLE_H
+#ifndef ANDROID_AAUDIO_SHARED_REGION_PARCELABLE_H
+#define ANDROID_AAUDIO_SHARED_REGION_PARCELABLE_H
#include <stdint.h>
@@ -59,4 +59,4 @@
} /* namespace aaudio */
-#endif //BINDING_SHAREDREGIONPARCELABLE_H
+#endif //ANDROID_AAUDIO_SHARED_REGION_PARCELABLE_H
diff --git a/media/libaaudio/src/client/AudioEndpoint.cpp b/media/libaaudio/src/client/AudioEndpoint.cpp
index 6f87df6..027d66d 100644
--- a/media/libaaudio/src/client/AudioEndpoint.cpp
+++ b/media/libaaudio/src/client/AudioEndpoint.cpp
@@ -28,6 +28,9 @@
using namespace android;
using namespace aaudio;
+#define RIDICULOUSLY_LARGE_BUFFER_CAPACITY (256 * 1024)
+#define RIDICULOUSLY_LARGE_FRAME_SIZE 4096
+
AudioEndpoint::AudioEndpoint()
: mOutputFreeRunning(false)
, mDataReadCounter(0)
@@ -45,16 +48,22 @@
ALOGE("AudioEndpoint_validateQueueDescriptor() NULL descriptor");
return AAUDIO_ERROR_NULL;
}
- if (descriptor->capacityInFrames <= 0) {
+
+ if (descriptor->capacityInFrames < 1
+ || descriptor->capacityInFrames > RIDICULOUSLY_LARGE_BUFFER_CAPACITY) {
ALOGE("AudioEndpoint_validateQueueDescriptor() bad capacityInFrames = %d",
descriptor->capacityInFrames);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
- if (descriptor->bytesPerFrame <= 1) {
+
+ // Reject extreme values to catch bugs and prevent numeric overflows.
+ if (descriptor->bytesPerFrame < 1
+ || descriptor->bytesPerFrame > RIDICULOUSLY_LARGE_FRAME_SIZE) {
ALOGE("AudioEndpoint_validateQueueDescriptor() bad bytesPerFrame = %d",
descriptor->bytesPerFrame);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
+
if (descriptor->dataAddress == nullptr) {
ALOGE("AudioEndpoint_validateQueueDescriptor() NULL dataAddress");
return AAUDIO_ERROR_NULL;
@@ -82,6 +91,7 @@
*descriptor->readCounterAddress = counter;
ALOGV("AudioEndpoint_validateQueueDescriptor() wrote readCounterAddress successfully");
}
+
if (descriptor->writeCounterAddress) {
fifo_counter_t counter = *descriptor->writeCounterAddress;
ALOGV("AudioEndpoint_validateQueueDescriptor() *writeCounterAddress = %d, now write",
@@ -89,6 +99,7 @@
*descriptor->writeCounterAddress = counter;
ALOGV("AudioEndpoint_validateQueueDescriptor() wrote writeCounterAddress successfully");
}
+
return AAUDIO_OK;
}
@@ -104,7 +115,6 @@
aaudio_result_t AudioEndpoint::configure(const EndpointDescriptor *pEndpointDescriptor)
{
- // TODO maybe remove after debugging
aaudio_result_t result = AudioEndpoint_validateDescriptor(pEndpointDescriptor);
if (result != AAUDIO_OK) {
ALOGE("AudioEndpoint_validateQueueDescriptor returned %d %s",
@@ -112,10 +122,19 @@
return result;
}
+ // ============================ up message queue =============================
const RingBufferDescriptor *descriptor = &pEndpointDescriptor->upMessageQueueDescriptor;
- assert(descriptor->bytesPerFrame == sizeof(AAudioServiceMessage));
- assert(descriptor->readCounterAddress != nullptr);
- assert(descriptor->writeCounterAddress != nullptr);
+ if(descriptor->bytesPerFrame != sizeof(AAudioServiceMessage)) {
+ ALOGE("AudioEndpoint::configure() bytesPerFrame != sizeof(AAudioServiceMessage) = %d",
+ descriptor->bytesPerFrame);
+ return AAUDIO_ERROR_INTERNAL;
+ }
+
+ if(descriptor->readCounterAddress == nullptr || descriptor->writeCounterAddress == nullptr) {
+ ALOGE("AudioEndpoint_validateQueueDescriptor() NULL counter address");
+ return AAUDIO_ERROR_NULL;
+ }
+
mUpCommandQueue = new FifoBuffer(
descriptor->bytesPerFrame,
descriptor->capacityInFrames,
@@ -123,25 +142,9 @@
descriptor->writeCounterAddress,
descriptor->dataAddress
);
- /* TODO mDownCommandQueue
- if (descriptor->capacityInFrames > 0) {
- descriptor = &pEndpointDescriptor->downMessageQueueDescriptor;
- mDownCommandQueue = new FifoBuffer(
- descriptor->capacityInFrames,
- descriptor->bytesPerFrame,
- descriptor->readCounterAddress,
- descriptor->writeCounterAddress,
- descriptor->dataAddress
- );
- }
- */
+
+ // ============================ down data queue =============================
descriptor = &pEndpointDescriptor->downDataQueueDescriptor;
- assert(descriptor->capacityInFrames > 0);
- assert(descriptor->bytesPerFrame > 1);
- assert(descriptor->bytesPerFrame < 4 * 16); // FIXME just for initial debugging
- assert(descriptor->framesPerBurst > 0);
- assert(descriptor->framesPerBurst < 8 * 1024); // FIXME just for initial debugging
- assert(descriptor->dataAddress != nullptr);
ALOGV("AudioEndpoint::configure() data framesPerBurst = %d", descriptor->framesPerBurst);
ALOGV("AudioEndpoint::configure() data readCounterAddress = %p", descriptor->readCounterAddress);
mOutputFreeRunning = descriptor->readCounterAddress == nullptr;
@@ -172,8 +175,6 @@
aaudio_result_t AudioEndpoint::writeDataNow(const void *buffer, int32_t numFrames)
{
- // TODO Make it easier for the AAudioStreamInternal to scale floats and write shorts
- // TODO Similar to block adapter write through technique. Add a DataConverter.
return mDownDataQueue->write(buffer, numFrames);
}
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index a24a705..46a3fc5 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAUDIO_AUDIO_ENDPOINT_H
-#define AAUDIO_AUDIO_ENDPOINT_H
+#ifndef ANDROID_AAUDIO_AUDIO_ENDPOINT_H
+#define ANDROID_AAUDIO_AUDIO_ENDPOINT_H
#include <aaudio/AAudio.h>
@@ -93,4 +93,4 @@
} // namespace aaudio
-#endif //AAUDIO_AUDIO_ENDPOINT_H
+#endif //ANDROID_AAUDIO_AUDIO_ENDPOINT_H
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 5214db8..eee860e 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -244,7 +244,7 @@
ALOGD("AudioStreamInternal(): callbackLoop() exiting, result = %d, isPlaying() = %d",
result, (int) isPlaying());
- return NULL; // TODO review
+ return NULL;
}
static void *aaudio_callback_thread_proc(void *context)
@@ -402,7 +402,7 @@
aaudio_result_t AudioStreamInternal::getTimestamp(clockid_t clockId,
int64_t *framePosition,
int64_t *timeNanoseconds) {
- // TODO implement using real HAL
+ // TODO Generate in server and pass to client. Return latest.
int64_t time = AudioClock::getNanoseconds();
*framePosition = mClockModel.convertTimeToPosition(time);
*timeNanoseconds = time + (10 * AAUDIO_NANOS_PER_MILLISECOND); // Fake hardware delay
@@ -574,12 +574,9 @@
// Write as much data as we can without blocking.
aaudio_result_t AudioStreamInternal::writeNow(const void *buffer, int32_t numFrames,
int64_t currentNanoTime, int64_t *wakeTimePtr) {
-
- {
- aaudio_result_t result = processCommands();
- if (result != AAUDIO_OK) {
- return result;
- }
+ aaudio_result_t result = processCommands();
+ if (result != AAUDIO_OK) {
+ return result;
}
if (mAudioEndpoint.isOutputFreeRunning()) {
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index a43f6c5..ee602c1 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAUDIO_AUDIOSTREAMINTERNAL_H
-#define AAUDIO_AUDIOSTREAMINTERNAL_H
+#ifndef ANDROID_AAUDIO_AUDIO_STREAM_INTERNAL_H
+#define ANDROID_AAUDIO_AUDIO_STREAM_INTERNAL_H
#include <stdint.h>
#include <aaudio/AAudio.h>
@@ -49,15 +49,11 @@
aaudio_result_t requestStop() override;
- // TODO use aaudio_clockid_t all the way down to AudioClock
aaudio_result_t getTimestamp(clockid_t clockId,
int64_t *framePosition,
int64_t *timeNanoseconds) override;
-
-
virtual aaudio_result_t updateStateWhileWaiting() override;
-
// =========== End ABSTRACT methods ===========================
aaudio_result_t open(const AudioStreamBuilder &builder) override;
@@ -170,4 +166,4 @@
} /* namespace aaudio */
-#endif //AAUDIO_AUDIOSTREAMINTERNAL_H
+#endif //ANDROID_AAUDIO_AUDIO_STREAM_INTERNAL_H
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 205c341..0314f55 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
-#define AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
+#ifndef ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
+#define ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
#include <stdint.h>
@@ -106,4 +106,4 @@
} /* namespace aaudio */
-#endif //AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
+#endif //ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index c3cf27f..d1698bf 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -66,6 +66,18 @@
ALOGE("AudioStream::open(): samplesPerFrame out of range = %d", mSamplesPerFrame);
return AAUDIO_ERROR_OUT_OF_RANGE;
}
+
+ switch(mFormat) {
+ case AAUDIO_FORMAT_UNSPECIFIED:
+ case AAUDIO_FORMAT_PCM_I16:
+ case AAUDIO_FORMAT_PCM_FLOAT:
+ break; // valid
+ default:
+ ALOGE("AudioStream::open(): audioFormat not valid = %d", mFormat);
+ return AAUDIO_ERROR_INVALID_FORMAT;
+ // break;
+ }
+
if (mSampleRate < 0 || mSampleRate > 1000000) {
ALOGE("AudioStream::open(): mSampleRate out of range = %d", mSampleRate);
return AAUDIO_ERROR_INVALID_RATE;
@@ -101,7 +113,6 @@
return result;
}
- // TODO replace this when similar functionality added to AudioTrack.cpp
int64_t durationNanos = 20 * AAUDIO_NANOS_PER_MILLISECOND; // arbitrary
aaudio_stream_state_t state = getState();
while (state == currentState && timeoutNanoseconds > 0) {
@@ -145,6 +156,8 @@
return audioStream->wrapUserThread();
}
+// This is not exposed in the API.
+// But it is still used internally to implement callbacks for MMAP mode.
aaudio_result_t AudioStream::createThread(int64_t periodNanoseconds,
aaudio_audio_thread_proc_t threadProc,
void* threadArg)
@@ -161,8 +174,7 @@
setPeriodNanoseconds(periodNanoseconds);
int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
if (err != 0) {
- // TODO convert errno to aaudio_result_t
- return AAUDIO_ERROR_INTERNAL;
+ return AAudioConvert_androidToAAudioResult(-errno);
} else {
mHasThread = true;
return AAUDIO_OK;
@@ -182,7 +194,6 @@
int err = pthread_join(mThread, returnArg);
#endif
mHasThread = false;
- // TODO convert errno to aaudio_result_t
- return err ? AAUDIO_ERROR_INTERNAL : mThreadRegistrationResult;
+ return err ? AAudioConvert_androidToAAudioResult(-errno) : mThreadRegistrationResult;
}
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
index 59d754a..f89234a 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.cpp
@@ -108,3 +108,24 @@
break;
}
}
+
+aaudio_result_t AudioStreamLegacy::getBestTimestamp(clockid_t clockId,
+ int64_t *framePosition,
+ int64_t *timeNanoseconds,
+ ExtendedTimestamp *extendedTimestamp) {
+ int timebase;
+ switch (clockId) {
+ case CLOCK_BOOTTIME:
+ timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
+ break;
+ case CLOCK_MONOTONIC:
+ timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
+ break;
+ default:
+ ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
+ return AAUDIO_ERROR_UNEXPECTED_VALUE;
+ break;
+ }
+ status_t status = extendedTimestamp->getBestTimestamp(framePosition, timeNanoseconds, timebase);
+ return AAudioConvert_androidToAAudioResult(status);
+}
diff --git a/media/libaaudio/src/legacy/AudioStreamLegacy.h b/media/libaaudio/src/legacy/AudioStreamLegacy.h
index d5a3ede..38f1a56 100644
--- a/media/libaaudio/src/legacy/AudioStreamLegacy.h
+++ b/media/libaaudio/src/legacy/AudioStreamLegacy.h
@@ -17,6 +17,7 @@
#ifndef LEGACY_AUDIO_STREAM_LEGACY_H
#define LEGACY_AUDIO_STREAM_LEGACY_H
+#include <media/AudioTimestamp.h>
#include <aaudio/AAudio.h>
@@ -73,6 +74,12 @@
virtual int64_t incrementClientFrameCounter(int32_t frames) = 0;
protected:
+
+ aaudio_result_t getBestTimestamp(clockid_t clockId,
+ int64_t *framePosition,
+ int64_t *timeNanoseconds,
+ android::ExtendedTimestamp *extendedTimestamp);
+
FixedBlockAdapter *mBlockAdapter = nullptr;
aaudio_wrapping_frames_t mPositionWhenStarting = 0;
int32_t mCallbackBufferSize = 0;
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 918f5dd..eb6bfd5 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -278,20 +278,5 @@
if (status != NO_ERROR) {
return AAudioConvert_androidToAAudioResult(status);
}
- // TODO Merge common code into AudioStreamLegacy after rebasing.
- int timebase;
- switch(clockId) {
- case CLOCK_BOOTTIME:
- timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
- break;
- case CLOCK_MONOTONIC:
- timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
- break;
- default:
- ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
- return AAUDIO_ERROR_UNEXPECTED_VALUE;
- break;
- }
- status = extendedTimestamp.getBestTimestamp(framePosition, timeNanoseconds, timebase);
- return AAudioConvert_androidToAAudioResult(status);
+ return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp);
}
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index b4b1c04..a7c7673 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -61,7 +61,7 @@
ALOGD("AudioStreamTrack::open = %p", this);
// Try to create an AudioTrack
- // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified.
+ // Use stereo if unspecified.
int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
? 2 : getSamplesPerFrame();
audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
@@ -163,9 +163,8 @@
aaudio_result_t AudioStreamTrack::close()
{
- // TODO maybe add close() or release() to AudioTrack API then call it from here
if (getState() != AAUDIO_STREAM_STATE_CLOSED) {
- mAudioTrack.clear(); // TODO is this right?
+ mAudioTrack.clear();
setState(AAUDIO_STREAM_STATE_CLOSED);
}
mFixedBlockReader.close();
@@ -290,7 +289,7 @@
if (err != OK) {
return AAudioConvert_androidToAAudioResult(err);
} else if (position == 0) {
- // Advance frames read to match written.
+ // TODO Advance frames read to match written.
setState(AAUDIO_STREAM_STATE_FLUSHED);
}
}
@@ -389,20 +388,5 @@
if (status != NO_ERROR) {
return AAudioConvert_androidToAAudioResult(status);
}
- // TODO Merge common code into AudioStreamLegacy after rebasing.
- int timebase;
- switch (clockId) {
- case CLOCK_BOOTTIME:
- timebase = ExtendedTimestamp::TIMEBASE_BOOTTIME;
- break;
- case CLOCK_MONOTONIC:
- timebase = ExtendedTimestamp::TIMEBASE_MONOTONIC;
- break;
- default:
- ALOGE("getTimestamp() - Unrecognized clock type %d", (int) clockId);
- return AAUDIO_ERROR_UNEXPECTED_VALUE;
- break;
- }
- status = extendedTimestamp.getBestTimestamp(framePosition, timeNanoseconds, timebase);
- return AAudioConvert_androidToAAudioResult(status);
+ return getBestTimestamp(clockId, framePosition, timeNanoseconds, &extendedTimestamp);
}
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index 5fa228a..be2bd10 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -48,7 +48,7 @@
}
-// TODO call clamp16_from_float function in primitives.h
+// TODO expose and call clamp16_from_float function in primitives.h
static inline int16_t clamp16_from_float(float f) {
/* Offset is used to expand the valid range of [-1.0, 1.0) into the 16 lsbs of the
* floating point significand. The normal shift is 3<<22, but the -15 offset
@@ -209,18 +209,32 @@
status = DEAD_OBJECT;
break;
case AAUDIO_ERROR_INVALID_STATE:
+ case AAUDIO_ERROR_UNEXPECTED_STATE:
status = INVALID_OPERATION;
break;
- case AAUDIO_ERROR_UNEXPECTED_VALUE: // TODO redundant?
+ case AAUDIO_ERROR_UNEXPECTED_VALUE:
case AAUDIO_ERROR_INVALID_RATE:
case AAUDIO_ERROR_INVALID_FORMAT:
case AAUDIO_ERROR_ILLEGAL_ARGUMENT:
+ case AAUDIO_ERROR_OUT_OF_RANGE:
status = BAD_VALUE;
break;
case AAUDIO_ERROR_WOULD_BLOCK:
status = WOULD_BLOCK;
break;
- // TODO add more result codes
+ case AAUDIO_ERROR_NULL:
+ status = UNEXPECTED_NULL;
+ break;
+ // TODO translate these result codes
+ case AAUDIO_ERROR_INCOMPATIBLE:
+ case AAUDIO_ERROR_INTERNAL:
+ case AAUDIO_ERROR_INVALID_QUERY:
+ case AAUDIO_ERROR_UNIMPLEMENTED:
+ case AAUDIO_ERROR_UNAVAILABLE:
+ case AAUDIO_ERROR_NO_FREE_HANDLES:
+ case AAUDIO_ERROR_NO_MEMORY:
+ case AAUDIO_ERROR_TIMEOUT:
+ case AAUDIO_ERROR_NO_SERVICE:
default:
status = UNKNOWN_ERROR;
break;
@@ -244,13 +258,15 @@
case INVALID_OPERATION:
result = AAUDIO_ERROR_INVALID_STATE;
break;
- case BAD_VALUE:
- result = AAUDIO_ERROR_UNEXPECTED_VALUE;
- break;
+ case UNEXPECTED_NULL:
+ result = AAUDIO_ERROR_NULL;
+ break;
+ case BAD_VALUE:
+ result = AAUDIO_ERROR_UNEXPECTED_VALUE;
+ break;
case WOULD_BLOCK:
result = AAUDIO_ERROR_WOULD_BLOCK;
break;
- // TODO add more status codes
default:
result = AAUDIO_ERROR_INTERNAL;
break;
diff --git a/media/libaaudio/src/utility/FixedBlockAdapter.cpp b/media/libaaudio/src/utility/FixedBlockAdapter.cpp
index f4666af..63495f0 100644
--- a/media/libaaudio/src/utility/FixedBlockAdapter.cpp
+++ b/media/libaaudio/src/utility/FixedBlockAdapter.cpp
@@ -25,7 +25,7 @@
int32_t FixedBlockAdapter::open(int32_t bytesPerFixedBlock)
{
mSize = bytesPerFixedBlock;
- mStorage = new uint8_t[bytesPerFixedBlock]; // TODO use std::nothrow
+ mStorage = new uint8_t[bytesPerFixedBlock];
mPosition = 0;
return 0;
}
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index f050e7f..dc501b2 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -41,6 +41,7 @@
friend class MediaAnalyticsService;
friend class IMediaAnalyticsService;
friend class MediaMetricsJNI;
+ friend class MetricsSummarizer;
public:
@@ -231,7 +232,6 @@
size_t mPropCount;
size_t mPropSize;
Prop *mProps;
-
};
} // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 7079ff2..18fd857 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -275,20 +275,6 @@
ALOGV("MediaPlayerService created");
mNextConnId = 1;
- mBatteryAudio.refCount = 0;
- for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
- mBatteryAudio.deviceOn[i] = 0;
- mBatteryAudio.lastTime[i] = 0;
- mBatteryAudio.totalTime[i] = 0;
- }
- // speaker is on by default
- mBatteryAudio.deviceOn[SPEAKER] = 1;
-
- // reset battery stats
- // if the mediaserver has crashed, battery stats could be left
- // in bad state, reset the state upon service start.
- BatteryNotifier::getInstance().noteResetVideo();
-
MediaPlayerFactory::registerBuiltinFactories();
}
@@ -2486,7 +2472,31 @@
////////////////////////////////////////////////////////////////////////////////
-void MediaPlayerService::addBatteryData(uint32_t params)
+void MediaPlayerService::addBatteryData(uint32_t params) {
+ mBatteryTracker.addBatteryData(params);
+}
+
+status_t MediaPlayerService::pullBatteryData(Parcel* reply) {
+ return mBatteryTracker.pullBatteryData(reply);
+}
+
+MediaPlayerService::BatteryTracker::BatteryTracker() {
+ mBatteryAudio.refCount = 0;
+ for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
+ mBatteryAudio.deviceOn[i] = 0;
+ mBatteryAudio.lastTime[i] = 0;
+ mBatteryAudio.totalTime[i] = 0;
+ }
+ // speaker is on by default
+ mBatteryAudio.deviceOn[SPEAKER] = 1;
+
+ // reset battery stats
+ // if the mediaserver has crashed, battery stats could be left
+ // in bad state, reset the state upon service start.
+ BatteryNotifier::getInstance().noteResetVideo();
+}
+
+void MediaPlayerService::BatteryTracker::addBatteryData(uint32_t params)
{
Mutex::Autolock lock(mLock);
@@ -2626,7 +2636,7 @@
}
}
-status_t MediaPlayerService::pullBatteryData(Parcel* reply) {
+status_t MediaPlayerService::BatteryTracker::pullBatteryData(Parcel* reply) {
Mutex::Autolock lock(mLock);
// audio output devices usage
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 009fe73..06b9cad 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -246,51 +246,62 @@
CAMERA_PROCESS_DEATH = 4
};
- // For battery usage tracking purpose
- struct BatteryUsageInfo {
- // how many streams are being played by one UID
- int refCount;
- // a temp variable to store the duration(ms) of audio codecs
- // when we start a audio codec, we minus the system time from audioLastTime
- // when we pause it, we add the system time back to the audioLastTime
- // so after the pause, audioLastTime = pause time - start time
- // if multiple audio streams are played (or recorded), then audioLastTime
- // = the total playing time of all the streams
- int32_t audioLastTime;
- // when all the audio streams are being paused, we assign audioLastTime to
- // this variable, so this value could be provided to the battery app
- // in the next pullBatteryData call
- int32_t audioTotalTime;
-
- int32_t videoLastTime;
- int32_t videoTotalTime;
- };
- KeyedVector<int, BatteryUsageInfo> mBatteryData;
-
- enum {
- SPEAKER,
- OTHER_AUDIO_DEVICE,
- SPEAKER_AND_OTHER,
- NUM_AUDIO_DEVICES
- };
-
- struct BatteryAudioFlingerUsageInfo {
- int refCount; // how many audio streams are being played
- int deviceOn[NUM_AUDIO_DEVICES]; // whether the device is currently used
- int32_t lastTime[NUM_AUDIO_DEVICES]; // in ms
- // totalTime[]: total time of audio output devices usage
- int32_t totalTime[NUM_AUDIO_DEVICES]; // in ms
- };
-
- // This varialble is used to record the usage of audio output device
- // for battery app
- BatteryAudioFlingerUsageInfo mBatteryAudio;
-
// Collect info of the codec usage from media player and media recorder
virtual void addBatteryData(uint32_t params);
// API for the Battery app to pull the data of codecs usage
virtual status_t pullBatteryData(Parcel* reply);
private:
+ struct BatteryTracker {
+ BatteryTracker();
+ // Collect info of the codec usage from media player and media recorder
+ void addBatteryData(uint32_t params);
+ // API for the Battery app to pull the data of codecs usage
+ status_t pullBatteryData(Parcel* reply);
+
+ private:
+ // For battery usage tracking purpose
+ struct BatteryUsageInfo {
+ // how many streams are being played by one UID
+ int refCount;
+ // a temp variable to store the duration(ms) of audio codecs
+ // when we start a audio codec, we minus the system time from audioLastTime
+ // when we pause it, we add the system time back to the audioLastTime
+ // so after the pause, audioLastTime = pause time - start time
+ // if multiple audio streams are played (or recorded), then audioLastTime
+ // = the total playing time of all the streams
+ int32_t audioLastTime;
+ // when all the audio streams are being paused, we assign audioLastTime to
+ // this variable, so this value could be provided to the battery app
+ // in the next pullBatteryData call
+ int32_t audioTotalTime;
+
+ int32_t videoLastTime;
+ int32_t videoTotalTime;
+ };
+ KeyedVector<int, BatteryUsageInfo> mBatteryData;
+
+ enum {
+ SPEAKER,
+ OTHER_AUDIO_DEVICE,
+ SPEAKER_AND_OTHER,
+ NUM_AUDIO_DEVICES
+ };
+
+ struct BatteryAudioFlingerUsageInfo {
+ int refCount; // how many audio streams are being played
+ int deviceOn[NUM_AUDIO_DEVICES]; // whether the device is currently used
+ int32_t lastTime[NUM_AUDIO_DEVICES]; // in ms
+ // totalTime[]: total time of audio output devices usage
+ int32_t totalTime[NUM_AUDIO_DEVICES]; // in ms
+ };
+
+ // This varialble is used to record the usage of audio output device
+ // for battery app
+ BatteryAudioFlingerUsageInfo mBatteryAudio;
+
+ mutable Mutex mLock;
+ };
+ BatteryTracker mBatteryTracker;
class Client : public BnMediaPlayer {
// IMediaPlayer interface
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index cafedba..4f18a26 100755
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -72,8 +72,10 @@
static const int64_t kMaxMetadataSize = 0x4000000LL; // 64MB max per-frame metadata size
static const char kMetaKey_Version[] = "com.android.version";
-#ifdef SHOW_MODEL_BUILD
+static const char kMetaKey_Manufacturer[] = "com.android.manufacturer";
static const char kMetaKey_Model[] = "com.android.model";
+
+#ifdef SHOW_BUILD
static const char kMetaKey_Build[] = "com.android.build";
#endif
static const char kMetaKey_CaptureFps[] = "com.android.capture.fps";
@@ -93,7 +95,7 @@
kHevcNalUnitTypePrefixSei,
kHevcNalUnitTypeSuffixSei,
};
-/* uncomment to include model and build in meta */
+/* uncomment to include build in meta */
//#define SHOW_MODEL_BUILD 1
class MPEG4Writer::Track {
@@ -611,12 +613,20 @@
mMetaKeys->setString(kMetaKey_Version, val, n + 1);
mMoovExtraSize += sizeof(kMetaKey_Version) + n + 32;
}
-#ifdef SHOW_MODEL_BUILD
- if (property_get("ro.product.model", val, NULL)
- && (n = strlen(val)) > 0) {
- mMetaKeys->setString(kMetaKey_Model, val, n + 1);
- mMoovExtraSize += sizeof(kMetaKey_Model) + n + 32;
+
+ if (property_get_bool("media.recorder.show_manufacturer_and_model", false)) {
+ if (property_get("ro.product.manufacturer", val, NULL)
+ && (n = strlen(val)) > 0) {
+ mMetaKeys->setString(kMetaKey_Manufacturer, val, n + 1);
+ mMoovExtraSize += sizeof(kMetaKey_Manufacturer) + n + 32;
+ }
+ if (property_get("ro.product.model", val, NULL)
+ && (n = strlen(val)) > 0) {
+ mMetaKeys->setString(kMetaKey_Model, val, n + 1);
+ mMoovExtraSize += sizeof(kMetaKey_Model) + n + 32;
+ }
}
+#ifdef SHOW_MODEL_BUILD
if (property_get("ro.build.display.id", val, NULL)
&& (n = strlen(val)) > 0) {
mMetaKeys->setString(kMetaKey_Build, val, n + 1);
diff --git a/media/libstagefright/omx/1.0/Omx.cpp b/media/libstagefright/omx/1.0/Omx.cpp
index 365ea5d..64b2c08 100644
--- a/media/libstagefright/omx/1.0/Omx.cpp
+++ b/media/libstagefright/omx/1.0/Omx.cpp
@@ -180,26 +180,22 @@
return OK;
}
- wp<IBase> observer;
{
Mutex::Autolock autoLock(mLock);
ssize_t observerIndex = mNode2Observer.indexOfKey(instance.get());
- if (observerIndex < 0) {
- return OK;
- }
- observer = mNode2Observer.valueAt(observerIndex);
- ssize_t nodeIndex = mLiveNodes.indexOfKey(observer);
- if (nodeIndex < 0) {
- return OK;
- }
- mNode2Observer.removeItemsAt(observerIndex);
- mLiveNodes.removeItemsAt(nodeIndex);
- }
-
- {
- sp<IBase> sObserver = observer.promote();
- if (sObserver != nullptr) {
- sObserver->unlinkToDeath(this);
+ if (observerIndex >= 0) {
+ wp<IBase> observer = mNode2Observer.valueAt(observerIndex);
+ ssize_t nodeIndex = mLiveNodes.indexOfKey(observer);
+ if (nodeIndex >= 0) {
+ mNode2Observer.removeItemsAt(observerIndex);
+ mLiveNodes.removeItemsAt(nodeIndex);
+ sp<IBase> sObserver = observer.promote();
+ if (sObserver != nullptr) {
+ sObserver->unlinkToDeath(this);
+ }
+ } else {
+ LOG(WARNING) << "Inconsistent observer record";
+ }
}
}
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index 836972a..e06a81f 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -93,10 +93,6 @@
}
if (mFlashControl == NULL) {
- if (enabled == false) {
- return OK;
- }
-
res = createFlashlightControl(cameraId);
if (res) {
return res;
@@ -139,10 +135,14 @@
cameraIds[i] = String8(ids[i].c_str());
}
- mHasFlashlightMap.clear();
- mFlashlightMapInitialized = false;
+ mFlashControl.clear();
for (auto &id : cameraIds) {
+ ssize_t index = mHasFlashlightMap.indexOfKey(id);
+ if (0 <= index) {
+ continue;
+ }
+
bool hasFlash = false;
res = createFlashlightControl(id);
if (res) {
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 0031441..415fdf5 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -198,13 +198,17 @@
}
status_t CameraService::enumerateProviders() {
- mCameraProviderManager = new CameraProviderManager();
status_t res;
- res = mCameraProviderManager->initialize(this);
- if (res != OK) {
- ALOGE("%s: Unable to initialize camera provider manager: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
+ Mutex::Autolock l(mServiceLock);
+
+ if (nullptr == mCameraProviderManager.get()) {
+ mCameraProviderManager = new CameraProviderManager();
+ res = mCameraProviderManager->initialize(this);
+ if (res != OK) {
+ ALOGE("%s: Unable to initialize camera provider manager: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
}
mNumberOfCameras = mCameraProviderManager->getCameraCount();
@@ -216,15 +220,25 @@
// TODO: maybe put this into CameraProviderManager::initialize()?
mCameraProviderManager->setUpVendorTags();
- mFlashlight = new CameraFlashlight(mCameraProviderManager, this);
+ if (nullptr == mFlashlight.get()) {
+ mFlashlight = new CameraFlashlight(mCameraProviderManager, this);
+ }
+
res = mFlashlight->findFlashUnits();
if (res != OK) {
ALOGE("Failed to enumerate flash units: %s (%d)", strerror(-res), res);
}
- // TODO: Verify device versions are in support
-
for (auto& cameraId : mCameraProviderManager->getCameraDeviceIds()) {
+ String8 id8 = String8(cameraId.c_str());
+ {
+ Mutex::Autolock lock(mCameraStatesLock);
+ auto iter = mCameraStates.find(id8);
+ if (iter != mCameraStates.end()) {
+ continue;
+ }
+ }
+
hardware::camera::common::V1_0::CameraResourceCost cost;
res = mCameraProviderManager->getResourceCost(cameraId, &cost);
if (res != OK) {
@@ -235,22 +249,19 @@
for (size_t i = 0; i < cost.conflictingDevices.size(); i++) {
conflicting.emplace(String8(cost.conflictingDevices[i].c_str()));
}
- String8 id8 = String8(cameraId.c_str());
Mutex::Autolock lock(mCameraStatesLock);
mCameraStates.emplace(id8,
std::make_shared<CameraState>(id8, cost.resourceCost, conflicting));
if (mFlashlight->hasFlashUnit(id8)) {
- mTorchStatusMap.add(id8,
- TorchModeStatus::AVAILABLE_OFF);
+ mTorchStatusMap.add(id8, TorchModeStatus::AVAILABLE_OFF);
}
}
return OK;
}
-
sp<ICameraServiceProxy> CameraService::getCameraServiceProxy() {
sp<ICameraServiceProxy> proxyBinder = nullptr;
#ifndef __BRILLO__
@@ -276,6 +287,10 @@
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
}
+void CameraService::onNewProviderRegistered() {
+ enumerateProviders();
+}
+
void CameraService::onDeviceStatusChanged(const String8& id,
CameraDeviceStatus newHalStatus) {
ALOGI("%s: Status changed for cameraId=%s, newStatus=%d", __FUNCTION__,
@@ -407,6 +422,7 @@
Status CameraService::getNumberOfCameras(int32_t type, int32_t* numCameras) {
ATRACE_CALL();
+ Mutex::Autolock l(mServiceLock);
switch (type) {
case CAMERA_TYPE_BACKWARD_COMPATIBLE:
*numCameras = mNumberOfNormalCameras;
@@ -426,6 +442,8 @@
Status CameraService::getCameraInfo(int cameraId,
CameraInfo* cameraInfo) {
ATRACE_CALL();
+ Mutex::Autolock l(mServiceLock);
+
if (!mInitialized) {
return STATUS_ERROR(ERROR_DISCONNECTED,
"Camera subsystem is not available");
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 7d81993..87603a3 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -99,6 +99,7 @@
hardware::camera::common::V1_0::CameraDeviceStatus newHalStatus) override;
virtual void onTorchStatusChanged(const String8& cameraId,
hardware::camera::common::V1_0::TorchModeStatus newStatus) override;
+ virtual void onNewProviderRegistered() override;
/////////////////////////////////////////////////////////////////////
// ICameraService
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 38fe1b6..65633db 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -231,7 +231,6 @@
status_t CameraProviderManager::setUpVendorTags() {
sp<VendorTagDescriptorCache> tagCache = new VendorTagDescriptorCache();
- VendorTagDescriptorCache::clearGlobalVendorTagCache();
for (auto& provider : mProviders) {
hardware::hidl_vec<VendorTagSection> vts;
Status status;
@@ -331,9 +330,17 @@
const hardware::hidl_string& /*fqName*/,
const hardware::hidl_string& name,
bool /*preexisting*/) {
- std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
- addProviderLocked(name);
+ addProviderLocked(name);
+ }
+
+ sp<StatusListener> listener = getStatusListener();
+ if (nullptr != listener.get()) {
+ listener->onNewProviderRegistered();
+ }
+
return hardware::Return<void>();
}
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 3afc1d9..9ba7f91 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -106,6 +106,7 @@
hardware::camera::common::V1_0::CameraDeviceStatus newStatus) = 0;
virtual void onTorchStatusChanged(const String8 &cameraId,
hardware::camera::common::V1_0::TorchModeStatus newStatus) = 0;
+ virtual void onNewProviderRegistered() = 0;
};
/**
diff --git a/services/mediaanalytics/Android.mk b/services/mediaanalytics/Android.mk
index f7197af..9e2813e 100644
--- a/services/mediaanalytics/Android.mk
+++ b/services/mediaanalytics/Android.mk
@@ -5,7 +5,12 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- main_mediametrics.cpp \
+ main_mediametrics.cpp \
+ MetricsSummarizerCodec.cpp \
+ MetricsSummarizerExtractor.cpp \
+ MetricsSummarizerPlayer.cpp \
+ MetricsSummarizerRecorder.cpp \
+ MetricsSummarizer.cpp \
MediaAnalyticsService.cpp
LOCAL_SHARED_LIBRARIES := \
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 35c1f5b..876c685 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -20,6 +20,7 @@
#define LOG_TAG "MediaAnalyticsService"
#include <utils/Log.h>
+#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -70,11 +71,28 @@
#include "MediaAnalyticsService.h"
+#include "MetricsSummarizer.h"
+#include "MetricsSummarizerCodec.h"
+#include "MetricsSummarizerExtractor.h"
+#include "MetricsSummarizerPlayer.h"
+#include "MetricsSummarizerRecorder.h"
+
namespace android {
-#define DEBUG_QUEUE 0
+
+// summarized records
+// up to 48 sets, each covering an hour -- at least 2 days of coverage
+// (will be longer if there are hours without any media action)
+static const nsecs_t kNewSetIntervalNs = 3600*(1000*1000*1000ll);
+static const int kMaxRecordSets = 48;
+// individual records kept in memory
+static const int kMaxRecords = 100;
+
+
+static const char *kServiceName = "media.metrics";
+
//using android::status_t;
//using android::OK;
@@ -85,18 +103,67 @@
void MediaAnalyticsService::instantiate() {
defaultServiceManager()->addService(
- String16("media.metrics"), new MediaAnalyticsService());
+ String16(kServiceName), new MediaAnalyticsService());
}
-// XXX: add dynamic controls for mMaxRecords
+// handle sets of summarizers
+MediaAnalyticsService::SummarizerSet::SummarizerSet() {
+ mSummarizers = new List<MetricsSummarizer *>();
+}
+MediaAnalyticsService::SummarizerSet::~SummarizerSet() {
+ // empty the list
+ List<MetricsSummarizer *> *l = mSummarizers;
+ while (l->size() > 0) {
+ MetricsSummarizer *summarizer = *(l->begin());
+ l->erase(l->begin());
+ delete summarizer;
+ }
+}
+
+void MediaAnalyticsService::newSummarizerSet() {
+ ALOGD("MediaAnalyticsService::newSummarizerSet");
+ MediaAnalyticsService::SummarizerSet *set = new MediaAnalyticsService::SummarizerSet();
+ nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+ set->setStarted(now);
+
+ set->appendSummarizer(new MetricsSummarizerExtractor("extractor"));
+ set->appendSummarizer(new MetricsSummarizerCodec("codec"));
+ set->appendSummarizer(new MetricsSummarizerPlayer("nuplayer"));
+ set->appendSummarizer(new MetricsSummarizerRecorder("recorder"));
+
+ // ALWAYS at the end, since it catches everything
+ set->appendSummarizer(new MetricsSummarizer(NULL));
+
+ // inject this set at the BACK of the list.
+ mSummarizerSets->push_back(set);
+ mCurrentSet = set;
+
+ // limit the # that we have
+ if (mMaxRecordSets > 0) {
+ List<SummarizerSet *> *l = mSummarizerSets;
+ while (l->size() > (size_t) mMaxRecordSets) {
+ ALOGD("Deleting oldest record set....");
+ MediaAnalyticsService::SummarizerSet *oset = *(l->begin());
+ l->erase(l->begin());
+ delete oset;
+ mSetsDiscarded++;
+ }
+ }
+}
+
MediaAnalyticsService::MediaAnalyticsService()
- : mMaxRecords(100) {
+ : mMaxRecords(kMaxRecords),
+ mMaxRecordSets(kMaxRecordSets),
+ mNewSetInterval(kNewSetIntervalNs) {
ALOGD("MediaAnalyticsService created");
// clear our queues
mOpen = new List<MediaAnalyticsItem *>();
mFinalized = new List<MediaAnalyticsItem *>();
+ mSummarizerSets = new List<MediaAnalyticsService::SummarizerSet *>();
+ newSummarizerSet();
+
mItemsSubmitted = 0;
mItemsFinalized = 0;
mItemsDiscarded = 0;
@@ -109,7 +176,13 @@
MediaAnalyticsService::~MediaAnalyticsService() {
ALOGD("MediaAnalyticsService destroyed");
- // XXX: clean out mOpen and mFinalized
+ // clean out mOpen and mFinalized
+ delete mOpen;
+ mOpen = NULL;
+ delete mFinalized;
+ mFinalized = NULL;
+
+ // XXX: clean out the summaries
}
@@ -145,7 +218,7 @@
case AID_MEDIA_EX:
case AID_MEDIA_DRM:
// trusted source, only override default values
- isTrusted = true;
+ isTrusted = true;
if (uid_given == (-1)) {
item->setUid(uid);
}
@@ -197,10 +270,12 @@
oitem = NULL;
} else {
oitem->setFinalized(true);
+ summarize(oitem);
saveItem(mFinalized, oitem, 0);
}
// new record could itself be marked finalized...
if (finalizing) {
+ summarize(item);
saveItem(mFinalized, item, 0);
mItemsFinalized++;
} else {
@@ -211,6 +286,7 @@
// combine the records, send it to finalized if appropriate
oitem->merge(item);
if (finalizing) {
+ summarize(oitem);
saveItem(mFinalized, oitem, 0);
mItemsFinalized++;
}
@@ -229,6 +305,7 @@
delete item;
item = NULL;
} else {
+ summarize(item);
saveItem(mFinalized, item, 0);
mItemsFinalized++;
}
@@ -239,26 +316,6 @@
return id;
}
-List<MediaAnalyticsItem *> *MediaAnalyticsService::getMediaAnalyticsItemList(bool finished, nsecs_t ts) {
- // this might never get called; the binder interface maps to the full parm list
- // on the client side before making the binder call.
- // but this lets us be sure...
- List<MediaAnalyticsItem*> *list;
- list = getMediaAnalyticsItemList(finished, ts, MediaAnalyticsItem::kKeyAny);
- return list;
-}
-
-List<MediaAnalyticsItem *> *MediaAnalyticsService::getMediaAnalyticsItemList(bool , nsecs_t , MediaAnalyticsItem::Key ) {
-
- // XXX: implement the get-item-list semantics
-
- List<MediaAnalyticsItem *> *list = NULL;
- // set up our query on the persistent data
- // slurp in all of the pieces
- // return that
- return list;
-}
-
status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 512;
@@ -277,15 +334,21 @@
// crack any parameters
bool clear = false;
+ bool summary = false;
nsecs_t ts_since = 0;
+ String16 summaryOption("-summary");
String16 clearOption("-clear");
String16 sinceOption("-since");
String16 helpOption("-help");
+ String16 onlyOption("-only");
+ const char *only = NULL;
int n = args.size();
for (int i = 0; i < n; i++) {
String8 myarg(args[i]);
if (args[i] == clearOption) {
clear = true;
+ } else if (args[i] == summaryOption) {
+ summary = true;
} else if (args[i] == sinceOption) {
i++;
if (i < n) {
@@ -301,12 +364,27 @@
}
// command line is milliseconds; internal units are nano-seconds
ts_since *= 1000*1000;
+ } else if (args[i] == onlyOption) {
+ i++;
+ if (i < n) {
+ String8 value(args[i]);
+ const char *p = value.string();
+ char *q = strdup(p);
+ if (q != NULL) {
+ if (only != NULL) {
+ free((void*)only);
+ }
+ only = q;
+ }
+ }
} else if (args[i] == helpOption) {
result.append("Recognized parameters:\n");
result.append("-help this help message\n");
+ result.append("-summary show summary info\n");
result.append("-clear clears out saved records\n");
- result.append("-since XXX include records since XXX\n");
- result.append(" (XXX is milliseconds since the UNIX epoch)\n");
+ result.append("-only X process records for component X\n");
+ result.append("-since X include records since X\n");
+ result.append(" (X is milliseconds since the UNIX epoch)\n");
write(fd, result.string(), result.size());
return NO_ERROR;
}
@@ -314,9 +392,42 @@
Mutex::Autolock _l(mLock);
- snprintf(buffer, SIZE, "Dump of the mediametrics process:\n");
+ // we ALWAYS dump this piece
+ snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
result.append(buffer);
+ dumpHeaders(result, ts_since);
+
+ // only want 1, to avoid confusing folks that parse the output
+ if (summary) {
+ dumpSummaries(result, ts_since, only);
+ } else {
+ dumpRecent(result, ts_since, only);
+ }
+
+
+ if (clear) {
+ // remove everything from the finalized queue
+ while (mFinalized->size() > 0) {
+ MediaAnalyticsItem * oitem = *(mFinalized->begin());
+ mFinalized->erase(mFinalized->begin());
+ delete oitem;
+ mItemsDiscarded++;
+ }
+
+ // shall we clear the summary data too?
+
+ }
+
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+// dump headers
+void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
+ const size_t SIZE = 512;
+ char buffer[SIZE];
+
int enabled = MediaAnalyticsItem::isEnabled();
if (enabled) {
snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
@@ -331,50 +442,71 @@
" Discarded: %" PRId64 "\n",
mItemsSubmitted, mItemsFinalized, mItemsDiscarded);
result.append(buffer);
+ snprintf(buffer, SIZE,
+ "Summary Sets Discarded: %" PRId64 "\n", mSetsDiscarded);
+ result.append(buffer);
if (ts_since != 0) {
snprintf(buffer, SIZE,
"Dumping Queue entries more recent than: %" PRId64 "\n",
(int64_t) ts_since);
result.append(buffer);
}
+}
+
+// dump summary info
+void MediaAnalyticsService::dumpSummaries(String8 &result, nsecs_t ts_since, const char *only) {
+ const size_t SIZE = 512;
+ char buffer[SIZE];
+ int slot = 0;
+
+ snprintf(buffer, SIZE, "\nSummarized Metrics:\n");
+ result.append(buffer);
+
+ // have each of the distillers dump records
+ if (mSummarizerSets != NULL) {
+ List<SummarizerSet *>::iterator itSet = mSummarizerSets->begin();
+ for (; itSet != mSummarizerSets->end(); itSet++) {
+ nsecs_t when = (*itSet)->getStarted();
+ if (when < ts_since) {
+ continue;
+ }
+ List<MetricsSummarizer *> *list = (*itSet)->getSummarizers();
+ List<MetricsSummarizer *>::iterator it = list->begin();
+ for (; it != list->end(); it++) {
+ if (only != NULL && strcmp(only, (*it)->getKey()) != 0) {
+ ALOGV("Told to omit '%s'", (*it)->getKey());
+ }
+ AString distilled = (*it)->dumpSummary(slot, only);
+ result.append(distilled.c_str());
+ }
+ }
+ }
+}
+
+// the recent, detailed queues
+void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only) {
+ const size_t SIZE = 512;
+ char buffer[SIZE];
// show the recently recorded records
snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
result.append(buffer);
- result.append(this->dumpQueue(mFinalized, ts_since));
+ result.append(this->dumpQueue(mFinalized, ts_since, only));
snprintf(buffer, sizeof(buffer), "\nIn-Progress Metrics (newest first):\n");
result.append(buffer);
- result.append(this->dumpQueue(mOpen, ts_since));
+ result.append(this->dumpQueue(mOpen, ts_since, only));
// show who is connected and injecting records?
// talk about # records fed to the 'readers'
// talk about # records we discarded, perhaps "discarded w/o reading" too
-
- if (clear) {
- // remove everything from the finalized queue
- while (mFinalized->size() > 0) {
- MediaAnalyticsItem * oitem = *(mFinalized->begin());
- if (DEBUG_QUEUE) {
- ALOGD("zap old record: key %s sessionID %" PRId64 " ts %" PRId64 "",
- oitem->getKey().c_str(), oitem->getSessionID(),
- oitem->getTimestamp());
- }
- mFinalized->erase(mFinalized->begin());
- mItemsDiscarded++;
- }
- }
-
- write(fd, result.string(), result.size());
- return NO_ERROR;
}
-
// caller has locked mLock...
String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList) {
- return dumpQueue(theList, (nsecs_t) 0);
+ return dumpQueue(theList, (nsecs_t) 0, NULL);
}
-String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since) {
+String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since, const char * only) {
String8 result;
int slot = 0;
@@ -387,6 +519,11 @@
if (when < ts_since) {
continue;
}
+ if (only != NULL &&
+ strcmp(only, (*it)->getKey().c_str()) != 0) {
+ ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
+ continue;
+ }
AString entry = (*it)->toString();
result.appendFormat("%5d: %s\n", slot, entry.c_str());
slot++;
@@ -405,13 +542,6 @@
Mutex::Autolock _l(mLock);
- if (DEBUG_QUEUE) {
- ALOGD("Inject a record: session %" PRId64 " ts %" PRId64 "",
- item->getSessionID(), item->getTimestamp());
- String8 before = dumpQueue(l);
- ALOGD("Q before insert: %s", before.string());
- }
-
// adding at back of queue (fifo order)
if (front) {
l->push_front(item);
@@ -419,30 +549,15 @@
l->push_back(item);
}
- if (DEBUG_QUEUE) {
- String8 after = dumpQueue(l);
- ALOGD("Q after insert: %s", after.string());
- }
-
// keep removing old records the front until we're in-bounds
if (mMaxRecords > 0) {
while (l->size() > (size_t) mMaxRecords) {
MediaAnalyticsItem * oitem = *(l->begin());
- if (DEBUG_QUEUE) {
- ALOGD("zap old record: key %s sessionID %" PRId64 " ts %" PRId64 "",
- oitem->getKey().c_str(), oitem->getSessionID(),
- oitem->getTimestamp());
- }
l->erase(l->begin());
delete oitem;
mItemsDiscarded++;
}
}
-
- if (DEBUG_QUEUE) {
- String8 after = dumpQueue(l);
- ALOGD("Q after cleanup: %s", after.string());
- }
}
// are they alike enough that nitem can be folded into oitem?
@@ -515,29 +630,14 @@
Mutex::Autolock _l(mLock);
- if(DEBUG_QUEUE) {
- String8 before = dumpQueue(l);
- ALOGD("Q before delete: %s", before.string());
- }
-
for (List<MediaAnalyticsItem *>::iterator it = l->begin();
it != l->end(); it++) {
if ((*it)->getSessionID() != item->getSessionID())
continue;
-
- if (DEBUG_QUEUE) {
- ALOGD(" --- removing record for SessionID %" PRId64 "", item->getSessionID());
- ALOGD("drop record at %s:%d", __FILE__, __LINE__);
- }
delete *it;
l->erase(it);
break;
}
-
- if (DEBUG_QUEUE) {
- String8 after = dumpQueue(l);
- ALOGD("Q after delete: %s", after.string());
- }
}
static AString allowedKeys[] =
@@ -579,5 +679,43 @@
return false;
}
+// insert into the appropriate summarizer.
+// we make our own copy to save/summarize
+void MediaAnalyticsService::summarize(MediaAnalyticsItem *item) {
+
+ ALOGV("MediaAnalyticsService::summarize()");
+
+ if (item == NULL) {
+ return;
+ }
+
+ nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+ if (mCurrentSet == NULL
+ || (mCurrentSet->getStarted() + mNewSetInterval < now)) {
+ newSummarizerSet();
+ }
+
+ if (mCurrentSet == NULL) {
+ return;
+ }
+
+ List<MetricsSummarizer *> *summarizers = mCurrentSet->getSummarizers();
+ List<MetricsSummarizer *>::iterator it = summarizers->begin();
+ for (; it != summarizers->end(); it++) {
+ if ((*it)->isMine(*item)) {
+ break;
+ }
+ }
+ if (it == summarizers->end()) {
+ ALOGD("no handler for type %s", item->getKey().c_str());
+ return; // no handler
+ }
+
+ // invoke the summarizer. summarizer will make whatever copies
+ // it wants; the caller retains ownership of item.
+
+ (*it)->handleRecord(item);
+
+}
} // namespace android
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index d2b0f09..6685967 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -28,6 +28,8 @@
#include <media/IMediaAnalyticsService.h>
+#include "MetricsSummarizer.h"
+
namespace android {
@@ -39,12 +41,6 @@
// on this side, caller surrenders ownership
virtual int64_t submit(MediaAnalyticsItem *item, bool forcenew);
- virtual List<MediaAnalyticsItem *>
- *getMediaAnalyticsItemList(bool finished, int64_t ts);
- virtual List<MediaAnalyticsItem *>
- *getMediaAnalyticsItemList(bool finished, int64_t ts, MediaAnalyticsItem::Key key);
-
-
static void instantiate();
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -58,6 +54,7 @@
int64_t mItemsSubmitted;
int64_t mItemsFinalized;
int64_t mItemsDiscarded;
+ int64_t mSetsDiscarded;
MediaAnalyticsItem::SessionID_t mLastSessionID;
// partitioned a bit so we don't over serialize
@@ -67,6 +64,10 @@
// the most we hold in memory
// up to this many in each queue (open, finalized)
int32_t mMaxRecords;
+ // # of sets of summaries
+ int32_t mMaxRecordSets;
+ // nsecs until we start a new record set
+ nsecs_t mNewSetInterval;
// input validation after arrival from client
bool contentValid(MediaAnalyticsItem *item, bool isTrusted);
@@ -82,12 +83,47 @@
MediaAnalyticsItem *findItem(List<MediaAnalyticsItem *> *,
MediaAnalyticsItem *, bool removeit);
+ // summarizers
+ void summarize(MediaAnalyticsItem *item);
+ class SummarizerSet {
+ nsecs_t mStarted;
+ List<MetricsSummarizer *> *mSummarizers;
+
+ public:
+ void appendSummarizer(MetricsSummarizer *s) {
+ if (s) {
+ mSummarizers->push_back(s);
+ }
+ };
+ nsecs_t getStarted() { return mStarted;}
+ void setStarted(nsecs_t started) {mStarted = started;}
+ List<MetricsSummarizer *> *getSummarizers() { return mSummarizers;}
+
+ SummarizerSet();
+ ~SummarizerSet();
+ };
+ void newSummarizerSet();
+ List<SummarizerSet *> *mSummarizerSets;
+ SummarizerSet *mCurrentSet;
+ List<MetricsSummarizer *> *getFirstSet() {
+ List<SummarizerSet *>::iterator first = mSummarizerSets->begin();
+ if (first != mSummarizerSets->end()) {
+ return (*first)->getSummarizers();
+ }
+ return NULL;
+ }
+
void saveItem(MediaAnalyticsItem);
void saveItem(List<MediaAnalyticsItem *> *, MediaAnalyticsItem *, int);
void deleteItem(List<MediaAnalyticsItem *> *, MediaAnalyticsItem *);
+ // support for generating output
String8 dumpQueue(List<MediaAnalyticsItem*> *);
- String8 dumpQueue(List<MediaAnalyticsItem*> *, nsecs_t);
+ String8 dumpQueue(List<MediaAnalyticsItem*> *, nsecs_t, const char *only);
+
+ void dumpHeaders(String8 &result, nsecs_t ts_since);
+ void dumpSummaries(String8 &result, nsecs_t ts_since, const char * only);
+ void dumpRecent(String8 &result, nsecs_t ts_since, const char * only);
};
diff --git a/services/mediaanalytics/MetricsSummarizer.cpp b/services/mediaanalytics/MetricsSummarizer.cpp
new file mode 100644
index 0000000..6d5787e
--- /dev/null
+++ b/services/mediaanalytics/MetricsSummarizer.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2017 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 "MetricsSummarizer"
+#include <utils/Log.h>
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+
+#include <media/IMediaAnalyticsService.h>
+
+#include "MetricsSummarizer.h"
+
+
+namespace android {
+
+#define DEBUG_SORT 0
+#define DEBUG_QUEUE 0
+
+
+MetricsSummarizer::MetricsSummarizer(const char *key)
+ : mIgnorables(NULL)
+{
+ ALOGV("MetricsSummarizer::MetricsSummarizer");
+
+ if (key == NULL) {
+ mKey = key;
+ } else {
+ mKey = strdup(key);
+ }
+
+ mSummaries = new List<MediaAnalyticsItem *>();
+}
+
+MetricsSummarizer::~MetricsSummarizer()
+{
+ ALOGV("MetricsSummarizer::~MetricsSummarizer");
+ if (mKey) {
+ free((void *)mKey);
+ mKey = NULL;
+ }
+
+ // clear the list of items we have saved
+ while (mSummaries->size() > 0) {
+ MediaAnalyticsItem * oitem = *(mSummaries->begin());
+ if (DEBUG_QUEUE) {
+ ALOGD("zap old record: key %s sessionID %" PRId64 " ts %" PRId64 "",
+ oitem->getKey().c_str(), oitem->getSessionID(),
+ oitem->getTimestamp());
+ }
+ mSummaries->erase(mSummaries->begin());
+ delete oitem;
+ }
+}
+
+// so we know what summarizer we were using
+const char *MetricsSummarizer::getKey() {
+ const char *value = mKey;
+ if (value == NULL) {
+ value = "unknown";
+ }
+ return value;
+}
+
+// should the record be given to this summarizer
+bool MetricsSummarizer::isMine(MediaAnalyticsItem &item)
+{
+ if (mKey == NULL)
+ return true;
+ AString itemKey = item.getKey();
+ if (strcmp(mKey, itemKey.c_str()) != 0) {
+ return false;
+ }
+ return true;
+}
+
+AString MetricsSummarizer::dumpSummary(int &slot)
+{
+ return dumpSummary(slot, NULL);
+}
+
+AString MetricsSummarizer::dumpSummary(int &slot, const char *only)
+{
+ AString value = "";
+
+ List<MediaAnalyticsItem *>::iterator it = mSummaries->begin();
+ if (it != mSummaries->end()) {
+ char buf[16]; // enough for "#####: "
+ for (; it != mSummaries->end(); it++) {
+ if (only != NULL && strcmp(only, (*it)->getKey().c_str()) != 0) {
+ continue;
+ }
+ AString entry = (*it)->toString();
+ snprintf(buf, sizeof(buf), "%5d: ", slot);
+ value.append(buf);
+ value.append(entry.c_str());
+ value.append("\n");
+ slot++;
+ }
+ }
+ return value;
+}
+
+void MetricsSummarizer::setIgnorables(const char **ignorables) {
+ mIgnorables = ignorables;
+}
+
+const char **MetricsSummarizer::getIgnorables() {
+ return mIgnorables;
+}
+
+void MetricsSummarizer::handleRecord(MediaAnalyticsItem *item) {
+
+ ALOGV("MetricsSummarizer::handleRecord() for %s",
+ item == NULL ? "<nothing>" : item->toString().c_str());
+
+ if (item == NULL) {
+ return;
+ }
+
+ List<MediaAnalyticsItem *>::iterator it = mSummaries->begin();
+ for (; it != mSummaries->end(); it++) {
+ bool good = sameAttributes((*it), item, getIgnorables());
+ ALOGV("Match against %s says %d",
+ (*it)->toString().c_str(), good);
+ if (good)
+ break;
+ }
+ if (it == mSummaries->end()) {
+ ALOGV("save new record");
+ item = item->dup();
+ if (item == NULL) {
+ ALOGE("unable to save MediaMetrics record");
+ }
+ sortProps(item);
+ item->setInt32("aggregated",1);
+ mSummaries->push_back(item);
+ } else {
+ ALOGV("increment existing record");
+ (*it)->addInt32("aggregated",1);
+ mergeRecord(*(*it), *item);
+ }
+}
+
+void MetricsSummarizer::mergeRecord(MediaAnalyticsItem &/*have*/, MediaAnalyticsItem &/*item*/) {
+ // default is no further massaging.
+ ALOGV("MetricsSummarizer::mergeRecord() [default]");
+ return;
+}
+
+
+//
+// Comparators
+//
+
+// testing that all of 'single' is in 'summ'
+// and that the values match.
+// 'summ' may have extra fields.
+// 'ignorable' is a set of things that we don't worry about matching up
+// (usually time- or count-based values we'll sum elsewhere)
+bool MetricsSummarizer::sameAttributes(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignorable) {
+
+ if (single == NULL || summ == NULL) {
+ return false;
+ }
+ ALOGV("MetricsSummarizer::sameAttributes(): summ %s", summ->toString().c_str());
+ ALOGV("MetricsSummarizer::sameAttributes(): single %s", single->toString().c_str());
+
+ // this can be made better.
+ for(size_t i=0;i<single->mPropCount;i++) {
+ MediaAnalyticsItem::Prop *prop1 = &(single->mProps[i]);
+ const char *attrName = prop1->mName;
+ ALOGV("compare on attr '%s'", attrName);
+
+ // is it something we should ignore
+ if (ignorable != NULL) {
+ const char **ig = ignorable;
+ while (*ig) {
+ if (strcmp(*ig, attrName) == 0) {
+ break;
+ }
+ ig++;
+ }
+ if (*ig) {
+ ALOGV("we don't mind that it has attr '%s'", attrName);
+ continue;
+ }
+ }
+
+ MediaAnalyticsItem::Prop *prop2 = summ->findProp(attrName);
+ if (prop2 == NULL) {
+ ALOGV("summ doesn't have this attr");
+ return false;
+ }
+ if (prop1->mType != prop2->mType) {
+ ALOGV("mismatched attr types");
+ return false;
+ }
+ switch (prop1->mType) {
+ case MediaAnalyticsItem::kTypeInt32:
+ if (prop1->u.int32Value != prop2->u.int32Value)
+ return false;
+ break;
+ case MediaAnalyticsItem::kTypeInt64:
+ if (prop1->u.int64Value != prop2->u.int64Value)
+ return false;
+ break;
+ case MediaAnalyticsItem::kTypeDouble:
+ // XXX: watch out for floating point comparisons!
+ if (prop1->u.doubleValue != prop2->u.doubleValue)
+ return false;
+ break;
+ case MediaAnalyticsItem::kTypeCString:
+ if (strcmp(prop1->u.CStringValue, prop2->u.CStringValue) != 0)
+ return false;
+ break;
+ case MediaAnalyticsItem::kTypeRate:
+ if (prop1->u.rate.count != prop2->u.rate.count)
+ return false;
+ if (prop1->u.rate.duration != prop2->u.rate.duration)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool MetricsSummarizer::sameAttributesId(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignorable) {
+
+ // verify same user
+ if (summ->mPid != single->mPid)
+ return false;
+
+ // and finally do the more expensive validation of the attributes
+ return sameAttributes(summ, single, ignorable);
+}
+
+int MetricsSummarizer::PropSorter(const void *a, const void *b) {
+ MediaAnalyticsItem::Prop *ai = (MediaAnalyticsItem::Prop *)a;
+ MediaAnalyticsItem::Prop *bi = (MediaAnalyticsItem::Prop *)b;
+ return strcmp(ai->mName, bi->mName);
+}
+
+// we sort in the summaries so that it looks pretty in the dumpsys
+void MetricsSummarizer::sortProps(MediaAnalyticsItem *item) {
+ if (item->mPropCount != 0) {
+ if (DEBUG_SORT) {
+ ALOGD("sortProps(pre): %s", item->toString().c_str());
+ }
+ qsort(item->mProps, item->mPropCount,
+ sizeof(MediaAnalyticsItem::Prop), MetricsSummarizer::PropSorter);
+ if (DEBUG_SORT) {
+ ALOGD("sortProps(pst): %s", item->toString().c_str());
+ }
+ }
+}
+
+} // namespace android
diff --git a/services/mediaanalytics/MetricsSummarizer.h b/services/mediaanalytics/MetricsSummarizer.h
new file mode 100644
index 0000000..0b64eac
--- /dev/null
+++ b/services/mediaanalytics/MetricsSummarizer.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 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_METRICSSUMMARIZER_H
+#define ANDROID_METRICSSUMMARIZER_H
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+
+#include <media/IMediaAnalyticsService.h>
+
+
+namespace android {
+
+class MetricsSummarizer
+{
+
+ public:
+
+ MetricsSummarizer(const char *key);
+ virtual ~MetricsSummarizer();
+
+ // show the key
+ const char * getKey();
+
+ // should the record be given to this summarizer
+ bool isMine(MediaAnalyticsItem &item);
+
+ // hand the record to this summarizer
+ void handleRecord(MediaAnalyticsItem *item);
+
+ virtual void mergeRecord(MediaAnalyticsItem &have, MediaAnalyticsItem &incoming);
+
+ // dump the summarized records (for dumpsys)
+ AString dumpSummary(int &slot);
+ AString dumpSummary(int &slot, const char *only);
+
+ void setIgnorables(const char **);
+ const char **getIgnorables();
+
+ protected:
+
+ // various comparators
+ // "do these records have same attributes and values in those attrs"
+ // ditto, but watch for "error" fields
+ bool sameAttributes(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignoreables);
+ // attributes + from the same app/userid
+ bool sameAttributesId(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignoreables);
+
+ static int PropSorter(const void *a, const void *b);
+ void sortProps(MediaAnalyticsItem *item);
+
+ private:
+ const char *mKey;
+ const char **mIgnorables;
+ List<MediaAnalyticsItem *> *mSummaries;
+
+
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_METRICSSUMMARIZER_H
diff --git a/services/mediaanalytics/MetricsSummarizerCodec.cpp b/services/mediaanalytics/MetricsSummarizerCodec.cpp
new file mode 100644
index 0000000..8c74782
--- /dev/null
+++ b/services/mediaanalytics/MetricsSummarizerCodec.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 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 "MetricsSummarizerCodec"
+#include <utils/Log.h>
+
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+
+#include <media/IMediaAnalyticsService.h>
+
+#include "MetricsSummarizer.h"
+#include "MetricsSummarizerCodec.h"
+
+
+
+
+namespace android {
+
+MetricsSummarizerCodec::MetricsSummarizerCodec(const char *key)
+ : MetricsSummarizer(key)
+{
+ ALOGV("MetricsSummarizerCodec::MetricsSummarizerCodec");
+}
+
+
+} // namespace android
diff --git a/services/mediaanalytics/MetricsSummarizerCodec.h b/services/mediaanalytics/MetricsSummarizerCodec.h
new file mode 100644
index 0000000..c01196f
--- /dev/null
+++ b/services/mediaanalytics/MetricsSummarizerCodec.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 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_METRICSSUMMARIZERCODEC_H
+#define ANDROID_METRICSSUMMARIZERCODEC_H
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+
+#include <media/IMediaAnalyticsService.h>
+#include "MetricsSummarizer.h"
+
+
+namespace android {
+
+class MetricsSummarizerCodec : public MetricsSummarizer
+{
+
+ public:
+
+ MetricsSummarizerCodec(const char *key);
+ virtual ~MetricsSummarizerCodec() {};
+
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_METRICSSUMMARIZERCODEC_H
diff --git a/services/mediaanalytics/MetricsSummarizerExtractor.cpp b/services/mediaanalytics/MetricsSummarizerExtractor.cpp
new file mode 100644
index 0000000..190f87d
--- /dev/null
+++ b/services/mediaanalytics/MetricsSummarizerExtractor.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 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 "MetricsSummarizerExtractor"
+#include <utils/Log.h>
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+
+#include <media/IMediaAnalyticsService.h>
+
+#include "MetricsSummarizer.h"
+#include "MetricsSummarizerExtractor.h"
+
+
+
+
+namespace android {
+
+MetricsSummarizerExtractor::MetricsSummarizerExtractor(const char *key)
+ : MetricsSummarizer(key)
+{
+ ALOGV("MetricsSummarizerExtractor::MetricsSummarizerExtractor");
+}
+
+} // namespace android
diff --git a/services/mediaanalytics/MetricsSummarizerExtractor.h b/services/mediaanalytics/MetricsSummarizerExtractor.h
new file mode 100644
index 0000000..eee052b
--- /dev/null
+++ b/services/mediaanalytics/MetricsSummarizerExtractor.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 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_METRICSSUMMARIZEREXTRACTOR_H
+#define ANDROID_METRICSSUMMARIZEREXTRACTOR_H
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+
+#include <media/IMediaAnalyticsService.h>
+#include "MetricsSummarizer.h"
+
+
+namespace android {
+
+class MetricsSummarizerExtractor : public MetricsSummarizer
+{
+
+ public:
+
+ MetricsSummarizerExtractor(const char *key);
+ virtual ~MetricsSummarizerExtractor() {};
+
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_METRICSSUMMARIZEREXTRACTOR_H
diff --git a/services/mediaanalytics/MetricsSummarizerPlayer.cpp b/services/mediaanalytics/MetricsSummarizerPlayer.cpp
new file mode 100644
index 0000000..5162059
--- /dev/null
+++ b/services/mediaanalytics/MetricsSummarizerPlayer.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 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 "MetricsSummarizerPlayer"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+
+#include <media/IMediaAnalyticsService.h>
+
+#include "MetricsSummarizer.h"
+#include "MetricsSummarizerPlayer.h"
+
+
+
+
+namespace android {
+
+static const char *player_ignorable[] = {
+ "android.media.mediaplayer.durationMs",
+ "android.media.mediaplayer.playingMs",
+ "android.media.mediaplayer.frames",
+ "android.media.mediaplayer.dropped",
+ 0
+};
+
+MetricsSummarizerPlayer::MetricsSummarizerPlayer(const char *key)
+ : MetricsSummarizer(key)
+{
+ ALOGV("MetricsSummarizerPlayer::MetricsSummarizerPlayer");
+ setIgnorables(player_ignorable);
+}
+
+void MetricsSummarizerPlayer::mergeRecord(MediaAnalyticsItem &summation, MediaAnalyticsItem &item) {
+
+ ALOGV("MetricsSummarizerPlayer::mergeRecord()");
+
+ //
+ // we sum time & frames.
+ // be careful about our special "-1" values that indicate 'unknown'
+ // treat those as 0 [basically, not summing them into the totals].
+ int64_t duration = 0;
+ if (item.getInt64("android.media.mediaplayer.durationMs", &duration)) {
+ ALOGV("found durationMs of %" PRId64, duration);
+ summation.addInt64("android.media.mediaplayer.durationMs",duration);
+ }
+ int64_t playing = 0;
+ if (item.getInt64("android.media.mediaplayer.playingMs", &playing))
+ ALOGV("found playingMs of %" PRId64, playing);
+ if (playing >= 0) {
+ summation.addInt64("android.media.mediaplayer.playingMs",playing);
+ }
+ int64_t frames = 0;
+ if (item.getInt64("android.media.mediaplayer.frames", &frames))
+ ALOGV("found framess of %" PRId64, frames);
+ if (frames >= 0) {
+ summation.addInt64("android.media.mediaplayer.frames",frames);
+ }
+ int64_t dropped = 0;
+ if (item.getInt64("android.media.mediaplayer.dropped", &dropped))
+ ALOGV("found dropped of %" PRId64, dropped);
+ if (dropped >= 0) {
+ summation.addInt64("android.media.mediaplayer.dropped",dropped);
+ }
+}
+
+} // namespace android
diff --git a/services/mediaanalytics/MetricsSummarizerPlayer.h b/services/mediaanalytics/MetricsSummarizerPlayer.h
new file mode 100644
index 0000000..ad1bf74
--- /dev/null
+++ b/services/mediaanalytics/MetricsSummarizerPlayer.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 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_METRICSSUMMARIZERPLAYER_H
+#define ANDROID_METRICSSUMMARIZERPLAYER_H
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+
+#include <media/IMediaAnalyticsService.h>
+#include "MetricsSummarizer.h"
+
+
+namespace android {
+
+class MetricsSummarizerPlayer : public MetricsSummarizer
+{
+
+ public:
+
+ MetricsSummarizerPlayer(const char *key);
+ virtual ~MetricsSummarizerPlayer() {};
+
+ virtual void mergeRecord(MediaAnalyticsItem &have, MediaAnalyticsItem &incoming);
+
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_METRICSSUMMARIZERPLAYER_H
diff --git a/services/mediaanalytics/MetricsSummarizerRecorder.cpp b/services/mediaanalytics/MetricsSummarizerRecorder.cpp
new file mode 100644
index 0000000..c2919c3
--- /dev/null
+++ b/services/mediaanalytics/MetricsSummarizerRecorder.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 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 "MetricsSummarizerRecorder"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+
+#include <media/IMediaAnalyticsService.h>
+
+#include "MetricsSummarizer.h"
+#include "MetricsSummarizerRecorder.h"
+
+
+
+
+namespace android {
+
+MetricsSummarizerRecorder::MetricsSummarizerRecorder(const char *key)
+ : MetricsSummarizer(key)
+{
+ ALOGV("MetricsSummarizerRecorder::MetricsSummarizerRecorder");
+}
+
+} // namespace android
diff --git a/services/mediaanalytics/MetricsSummarizerRecorder.h b/services/mediaanalytics/MetricsSummarizerRecorder.h
new file mode 100644
index 0000000..963baab
--- /dev/null
+++ b/services/mediaanalytics/MetricsSummarizerRecorder.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 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_METRICSSUMMARIZERRECORDER_H
+#define ANDROID_METRICSSUMMARIZERRECORDER_H
+
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/List.h>
+
+#include <media/IMediaAnalyticsService.h>
+#include "MetricsSummarizer.h"
+
+
+namespace android {
+
+class MetricsSummarizerRecorder : public MetricsSummarizer
+{
+
+ public:
+
+ MetricsSummarizerRecorder(const char *key);
+ virtual ~MetricsSummarizerRecorder() {};
+
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_METRICSSUMMARIZERRECORDER_H