summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/AudioTrack.h2
-rw-r--r--include/media/IOMX.h7
-rw-r--r--include/media/stagefright/MediaCodec.h2
-rw-r--r--media/libmedia/IOMX.cpp12
-rw-r--r--media/libmediaplayerservice/Android.mk1
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp25
-rw-r--r--media/libstagefright/ACodec.cpp6
-rw-r--r--media/libstagefright/Android.mk1
-rw-r--r--media/libstagefright/MediaCodec.cpp130
-rw-r--r--media/libstagefright/MediaCodecList.cpp18
-rw-r--r--media/libstagefright/MediaCodecListOverrides.cpp12
-rw-r--r--media/libstagefright/MediaCodecListOverrides.h3
-rw-r--r--media/libstagefright/OMXClient.cpp12
-rw-r--r--media/libstagefright/OMXCodec.cpp6
-rw-r--r--media/libstagefright/include/OMX.h4
-rw-r--r--media/libstagefright/include/OMXNodeInstance.h4
-rw-r--r--media/libstagefright/omx/OMX.cpp8
-rw-r--r--media/libstagefright/omx/OMXNodeInstance.cpp26
-rw-r--r--media/libstagefright/omx/tests/OMXHarness.cpp2
-rw-r--r--media/libstagefright/tests/MediaCodecListOverrides_test.cpp6
-rw-r--r--media/utils/Android.mk39
-rw-r--r--media/utils/BatteryNotifier.cpp213
-rw-r--r--media/utils/README4
-rw-r--r--media/utils/include/mediautils/BatteryNotifier.h73
-rw-r--r--services/camera/libcameraservice/Android.mk1
-rw-r--r--services/camera/libcameraservice/CameraService.cpp96
-rw-r--r--services/camera/libcameraservice/CameraService.h26
-rw-r--r--services/camera/libcameraservice/device3/Camera3Device.cpp62
-rw-r--r--services/camera/libcameraservice/device3/Camera3Device.h1
-rw-r--r--services/camera/libcameraservice/utils/ClientManager.h133
30 files changed, 677 insertions, 258 deletions
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index e9f0131..54e86b9 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -59,9 +59,11 @@ public:
// voluntary invalidation by mediaserver, or mediaserver crash.
EVENT_STREAM_END = 7, // Sent after all the buffers queued in AF and HW are played
// back (after stop is called)
+#if 0 // FIXME not yet implemented
EVENT_NEW_TIMESTAMP = 8, // Delivered periodically and when there's a significant change
// in the mapping from frame position to presentation time.
// See AudioTimestamp for the information included with event.
+#endif
};
/* Client should declare a Buffer and pass the address to obtainBuffer()
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index d33d142..46c363a 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -98,9 +98,10 @@ public:
virtual status_t getGraphicBufferUsage(
node_id node, OMX_U32 port_index, OMX_U32* usage) = 0;
+ // Use |params| as an OMX buffer, but limit the size of the OMX buffer to |allottedSize|.
virtual status_t useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer) = 0;
+ buffer_id *buffer, OMX_U32 allottedSize) = 0;
virtual status_t useGraphicBuffer(
node_id node, OMX_U32 port_index,
@@ -132,9 +133,11 @@ public:
node_id node, OMX_U32 port_index, size_t size,
buffer_id *buffer, void **buffer_data) = 0;
+ // Allocate an OMX buffer of size |allotedSize|. Use |params| as the backup buffer, which
+ // may be larger.
virtual status_t allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer) = 0;
+ buffer_id *buffer, OMX_U32 allottedSize) = 0;
virtual status_t freeBuffer(
node_id node, OMX_U32 port_index, buffer_id buffer) = 0;
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 6e14fc5..d62b35d 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -60,8 +60,6 @@ struct MediaCodec : public AHandler {
CB_RESOURCE_RECLAIMED = 5,
};
- struct BatteryNotifier;
-
static sp<MediaCodec> CreateByType(
const sp<ALooper> &looper, const char *mime, bool encoder, status_t *err = NULL);
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index c14debf..d556c33 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -245,12 +245,13 @@ public:
virtual status_t useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer) {
+ buffer_id *buffer, OMX_U32 allottedSize) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeInt32((int32_t)node);
data.writeInt32(port_index);
data.writeStrongBinder(IInterface::asBinder(params));
+ data.writeInt32(allottedSize);
remote()->transact(USE_BUFFER, data, &reply);
status_t err = reply.readInt32();
@@ -459,12 +460,13 @@ public:
virtual status_t allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer) {
+ buffer_id *buffer, OMX_U32 allottedSize) {
Parcel data, reply;
data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
data.writeInt32((int32_t)node);
data.writeInt32(port_index);
data.writeStrongBinder(IInterface::asBinder(params));
+ data.writeInt32(allottedSize);
remote()->transact(ALLOC_BUFFER_WITH_BACKUP, data, &reply);
status_t err = reply.readInt32();
@@ -757,9 +759,10 @@ status_t BnOMX::onTransact(
OMX_U32 port_index = data.readInt32();
sp<IMemory> params =
interface_cast<IMemory>(data.readStrongBinder());
+ OMX_U32 allottedSize = data.readInt32();
buffer_id buffer;
- status_t err = useBuffer(node, port_index, params, &buffer);
+ status_t err = useBuffer(node, port_index, params, &buffer, allottedSize);
reply->writeInt32(err);
if (err == OK) {
@@ -953,10 +956,11 @@ status_t BnOMX::onTransact(
OMX_U32 port_index = data.readInt32();
sp<IMemory> params =
interface_cast<IMemory>(data.readStrongBinder());
+ OMX_U32 allottedSize = data.readInt32();
buffer_id buffer;
status_t err = allocateBufferWithBackup(
- node, port_index, params, &buffer);
+ node, port_index, params, &buffer, allottedSize);
reply->writeInt32(err);
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index b52db97..7f0cca2 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -33,6 +33,7 @@ LOCAL_SHARED_LIBRARIES := \
libdl \
libgui \
libmedia \
+ libmediautils \
libsonivox \
libstagefright \
libstagefright_foundation \
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9c0af4a..7c40121 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -34,7 +34,6 @@
#include <utils/misc.h>
-#include <binder/IBatteryStats.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryHeapBase.h>
@@ -60,6 +59,7 @@
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooperRoster.h>
+#include <mediautils/BatteryNotifier.h>
#include <system/audio.h>
@@ -287,17 +287,9 @@ MediaPlayerService::MediaPlayerService()
// reset battery stats
// if the mediaserver has crashed, battery stats could be left
// in bad state, reset the state upon service start.
- const sp<IServiceManager> sm(defaultServiceManager());
- if (sm != NULL) {
- const String16 name("batterystats");
- // use checkService() to avoid blocking if service is not up yet
- sp<IBatteryStats> batteryStats =
- interface_cast<IBatteryStats>(sm->checkService(name));
- if (batteryStats != NULL) {
- batteryStats->noteResetVideo();
- batteryStats->noteResetAudio();
- }
- }
+ BatteryNotifier& notifier(BatteryNotifier::getInstance());
+ notifier.noteResetVideo();
+ notifier.noteResetAudio();
MediaPlayerFactory::registerBuiltinFactories();
}
@@ -1884,6 +1876,15 @@ void MediaPlayerService::AudioOutput::CallbackWrapper(
me->mCallbackCookie, CB_EVENT_TEAR_DOWN);
break;
+ case AudioTrack::EVENT_UNDERRUN:
+ // This occurs when there is no data available, typically occurring
+ // when there is a failure to supply data to the AudioTrack. It can also
+ // occur in non-offloaded mode when the audio device comes out of standby.
+ //
+ // If you see this at the start of playback, there probably was a glitch.
+ ALOGI("callbackwrapper: EVENT_UNDERRUN (discarded)");
+ break;
+
default:
ALOGE("received unknown event type: %d inside CallbackWrapper !", event);
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 70480a2..cd20979 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -725,9 +725,9 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) {
info.mData = new ABuffer(ptr, bufSize);
} else if (mQuirks & requiresAllocateBufferBit) {
err = mOMX->allocateBufferWithBackup(
- mNode, portIndex, mem, &info.mBufferID);
+ mNode, portIndex, mem, &info.mBufferID, def.nBufferSize);
} else {
- err = mOMX->useBuffer(mNode, portIndex, mem, &info.mBufferID);
+ err = mOMX->useBuffer(mNode, portIndex, mem, &info.mBufferID, def.nBufferSize);
}
if (mem != NULL) {
@@ -997,7 +997,7 @@ status_t ACodec::allocateOutputMetaDataBuffers() {
// we use useBuffer for metadata regardless of quirks
err = mOMX->useBuffer(
- mNode, kPortIndexOutput, mem, &info.mBufferID);
+ mNode, kPortIndexOutput, mem, &info.mBufferID, mem->size());
mBuffers[kPortIndexOutput].push(info);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 337068e..0dfa300 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -90,6 +90,7 @@ LOCAL_SHARED_LIBRARIES := \
libicuuc \
liblog \
libmedia \
+ libmediautils \
libnetd_client \
libopus \
libsonivox \
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 6f22e26..f918d2d 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -21,7 +21,6 @@
#include "include/avc_utils.h"
#include "include/SoftwareRenderer.h"
-#include <binder/IBatteryStats.h>
#include <binder/IMemory.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -48,6 +47,7 @@
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/PersistentSurface.h>
#include <media/stagefright/SurfaceUtils.h>
+#include <mediautils/BatteryNotifier.h>
#include <private/android_filesystem_config.h>
#include <utils/Log.h>
#include <utils/Singleton.h>
@@ -108,134 +108,6 @@ private:
DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient);
};
-struct MediaCodec::BatteryNotifier : public Singleton<BatteryNotifier> {
- BatteryNotifier();
- virtual ~BatteryNotifier();
-
- void noteStartVideo();
- void noteStopVideo();
- void noteStartAudio();
- void noteStopAudio();
- void onBatteryStatServiceDied();
-
-private:
- struct DeathNotifier : public IBinder::DeathRecipient {
- DeathNotifier() {}
- virtual void binderDied(const wp<IBinder>& /*who*/) {
- BatteryNotifier::getInstance().onBatteryStatServiceDied();
- }
- };
-
- Mutex mLock;
- int32_t mVideoRefCount;
- int32_t mAudioRefCount;
- sp<IBatteryStats> mBatteryStatService;
- sp<DeathNotifier> mDeathNotifier;
-
- sp<IBatteryStats> getBatteryService_l();
-
- DISALLOW_EVIL_CONSTRUCTORS(BatteryNotifier);
-};
-
-ANDROID_SINGLETON_STATIC_INSTANCE(MediaCodec::BatteryNotifier)
-
-MediaCodec::BatteryNotifier::BatteryNotifier() :
- mVideoRefCount(0),
- mAudioRefCount(0) {
-}
-
-sp<IBatteryStats> MediaCodec::BatteryNotifier::getBatteryService_l() {
- if (mBatteryStatService != NULL) {
- return mBatteryStatService;
- }
- // get battery service from service manager
- const sp<IServiceManager> sm(defaultServiceManager());
- if (sm != NULL) {
- const String16 name("batterystats");
- mBatteryStatService =
- interface_cast<IBatteryStats>(sm->getService(name));
- if (mBatteryStatService == NULL) {
- ALOGE("batterystats service unavailable!");
- return NULL;
- }
- mDeathNotifier = new DeathNotifier();
- IInterface::asBinder(mBatteryStatService)->linkToDeath(mDeathNotifier);
- // notify start now if media already started
- if (mVideoRefCount > 0) {
- mBatteryStatService->noteStartVideo(AID_MEDIA);
- }
- if (mAudioRefCount > 0) {
- mBatteryStatService->noteStartAudio(AID_MEDIA);
- }
- }
- return mBatteryStatService;
-}
-
-MediaCodec::BatteryNotifier::~BatteryNotifier() {
- if (mDeathNotifier != NULL) {
- IInterface::asBinder(mBatteryStatService)->
- unlinkToDeath(mDeathNotifier);
- }
-}
-
-void MediaCodec::BatteryNotifier::noteStartVideo() {
- Mutex::Autolock _l(mLock);
- sp<IBatteryStats> batteryService = getBatteryService_l();
- if (mVideoRefCount == 0 && batteryService != NULL) {
- batteryService->noteStartVideo(AID_MEDIA);
- }
- mVideoRefCount++;
-}
-
-void MediaCodec::BatteryNotifier::noteStopVideo() {
- Mutex::Autolock _l(mLock);
- if (mVideoRefCount == 0) {
- ALOGW("BatteryNotifier::noteStop(): video refcount is broken!");
- return;
- }
-
- sp<IBatteryStats> batteryService = getBatteryService_l();
-
- mVideoRefCount--;
- if (mVideoRefCount == 0 && batteryService != NULL) {
- batteryService->noteStopVideo(AID_MEDIA);
- }
-}
-
-void MediaCodec::BatteryNotifier::noteStartAudio() {
- Mutex::Autolock _l(mLock);
- sp<IBatteryStats> batteryService = getBatteryService_l();
- if (mAudioRefCount == 0 && batteryService != NULL) {
- batteryService->noteStartAudio(AID_MEDIA);
- }
- mAudioRefCount++;
-}
-
-void MediaCodec::BatteryNotifier::noteStopAudio() {
- Mutex::Autolock _l(mLock);
- if (mAudioRefCount == 0) {
- ALOGW("BatteryNotifier::noteStop(): audio refcount is broken!");
- return;
- }
-
- sp<IBatteryStats> batteryService = getBatteryService_l();
-
- mAudioRefCount--;
- if (mAudioRefCount == 0 && batteryService != NULL) {
- batteryService->noteStopAudio(AID_MEDIA);
- }
-}
-
-void MediaCodec::BatteryNotifier::onBatteryStatServiceDied() {
- Mutex::Autolock _l(mLock);
- mBatteryStatService.clear();
- mDeathNotifier.clear();
- // Do not reset mVideoRefCount and mAudioRefCount here. The ref
- // counting is independent of the battery service availability.
- // We need this if battery service becomes available after media
- // started.
-}
-
MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy() {
}
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 6708828..f366b1f 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -73,10 +73,24 @@ sp<IMediaCodecList> MediaCodecList::getLocalInstance() {
if (gCodecList->initCheck() == OK) {
sCodecList = gCodecList;
- struct stat s;
- if (stat(kProfilingResults, &s) == -1) {
+ FILE *resultsFile = fopen(kProfilingResults, "r");
+ if (resultsFile) {
+ AString currentVersion = getProfilingVersionString();
+ size_t currentVersionSize = currentVersion.size();
+ char *versionString = new char[currentVersionSize];
+ fgets(versionString, currentVersionSize, resultsFile);
+ if (strncmp(versionString, currentVersion.c_str(), currentVersionSize) != 0) {
+ // profiling result out of date
+ profilingNeeded = true;
+ }
+ fclose(resultsFile);
+ delete[] versionString;
+ } else {
// profiling results doesn't existed
profilingNeeded = true;
+ }
+
+ if (profilingNeeded) {
for (size_t i = 0; i < gCodecList->countCodecs(); ++i) {
infos.push_back(gCodecList->getCodecInfo(i));
}
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 006454d..a928163 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -20,6 +20,7 @@
#include "MediaCodecListOverrides.h"
+#include <cutils/properties.h>
#include <gui/Surface.h>
#include <media/ICrypto.h>
#include <media/IMediaCodecList.h>
@@ -34,6 +35,15 @@ namespace android {
const char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml";
+AString getProfilingVersionString() {
+ char val[PROPERTY_VALUE_MAX];
+ if (property_get("ro.build.display.id", val, NULL) && (strlen(val) > 0)) {
+ return AStringPrintf("<!-- Profiled-with: %s -->", val);
+ }
+
+ return "<!-- Profiled-with: UNKNOWN_BUILD_ID -->";
+}
+
// a limit to avoid allocating unreasonable number of codec instances in the measurement.
// this should be in sync with the MAX_SUPPORTED_INSTANCES defined in MediaCodecInfo.java.
static const int kMaxInstances = 32;
@@ -375,6 +385,8 @@ void exportResultsToXML(
}
AString overrides;
+ overrides.append(getProfilingVersionString());
+ overrides.append("\n");
overrides.append("<MediaCodecs>\n");
if (global_results.size() > 0) {
overrides.append(" <Settings>\n");
diff --git a/media/libstagefright/MediaCodecListOverrides.h b/media/libstagefright/MediaCodecListOverrides.h
index e350d2a..d4bb225 100644
--- a/media/libstagefright/MediaCodecListOverrides.h
+++ b/media/libstagefright/MediaCodecListOverrides.h
@@ -26,10 +26,13 @@
namespace android {
+extern const char *kProfilingVersionString;
extern const char *kProfilingResults;
struct MediaCodecInfo;
+AString getProfilingVersionString();
+
bool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2);
// profile codecs and save the result to xml file named kProfilingResults.
diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp
index f1ebea2..c91a37f 100644
--- a/media/libstagefright/OMXClient.cpp
+++ b/media/libstagefright/OMXClient.cpp
@@ -90,7 +90,7 @@ struct MuxOMX : public IOMX {
virtual status_t useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer);
+ buffer_id *buffer, OMX_U32 allottedSize);
virtual status_t useGraphicBuffer(
node_id node, OMX_U32 port_index,
@@ -120,7 +120,7 @@ struct MuxOMX : public IOMX {
virtual status_t allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer);
+ buffer_id *buffer, OMX_U32 allottedSize);
virtual status_t freeBuffer(
node_id node, OMX_U32 port_index, buffer_id buffer);
@@ -322,8 +322,8 @@ status_t MuxOMX::getGraphicBufferUsage(
status_t MuxOMX::useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer) {
- return getOMX(node)->useBuffer(node, port_index, params, buffer);
+ buffer_id *buffer, OMX_U32 allottedSize) {
+ return getOMX(node)->useBuffer(node, port_index, params, buffer, allottedSize);
}
status_t MuxOMX::useGraphicBuffer(
@@ -375,9 +375,9 @@ status_t MuxOMX::allocateBuffer(
status_t MuxOMX::allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer) {
+ buffer_id *buffer, OMX_U32 allottedSize) {
return getOMX(node)->allocateBufferWithBackup(
- node, port_index, params, buffer);
+ node, port_index, params, buffer, allottedSize);
}
status_t MuxOMX::freeBuffer(
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index aa6a7c0..927cc6c 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1678,7 +1678,7 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
&info.mData);
} else {
err = mOMX->allocateBufferWithBackup(
- mNode, portIndex, mem, &buffer);
+ mNode, portIndex, mem, &buffer, mem->size());
}
} else if (portIndex == kPortIndexOutput
&& (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
@@ -1690,10 +1690,10 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
&info.mData);
} else {
err = mOMX->allocateBufferWithBackup(
- mNode, portIndex, mem, &buffer);
+ mNode, portIndex, mem, &buffer, mem->size());
}
} else {
- err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
+ err = mOMX->useBuffer(mNode, portIndex, mem, &buffer, mem->size());
}
if (err != OK) {
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index c183208..fa1e03f 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -81,7 +81,7 @@ public:
virtual status_t useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer);
+ buffer_id *buffer, OMX_U32 allottedSize);
virtual status_t useGraphicBuffer(
node_id node, OMX_U32 port_index,
@@ -111,7 +111,7 @@ public:
virtual status_t allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer);
+ buffer_id *buffer, OMX_U32 allottedSize);
virtual status_t freeBuffer(
node_id node, OMX_U32 port_index, buffer_id buffer);
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index 3c032f9..e067598 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -70,7 +70,7 @@ struct OMXNodeInstance {
status_t useBuffer(
OMX_U32 portIndex, const sp<IMemory> &params,
- OMX::buffer_id *buffer);
+ OMX::buffer_id *buffer, OMX_U32 allottedSize);
status_t useGraphicBuffer(
OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
@@ -98,7 +98,7 @@ struct OMXNodeInstance {
status_t allocateBufferWithBackup(
OMX_U32 portIndex, const sp<IMemory> &params,
- OMX::buffer_id *buffer);
+ OMX::buffer_id *buffer, OMX_U32 allottedSize);
status_t freeBuffer(OMX_U32 portIndex, OMX::buffer_id buffer);
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index a1ceb2e..d46bf9d 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -352,9 +352,9 @@ status_t OMX::configureVideoTunnelMode(
status_t OMX::useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer) {
+ buffer_id *buffer, OMX_U32 allottedSize) {
return findInstance(node)->useBuffer(
- port_index, params, buffer);
+ port_index, params, buffer, allottedSize);
}
status_t OMX::useGraphicBuffer(
@@ -405,9 +405,9 @@ status_t OMX::allocateBuffer(
status_t OMX::allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> &params,
- buffer_id *buffer) {
+ buffer_id *buffer, OMX_U32 allottedSize) {
return findInstance(node)->allocateBufferWithBackup(
- port_index, params, buffer);
+ port_index, params, buffer, allottedSize);
}
status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 3dc1f7f..f5f0f4f 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -620,8 +620,11 @@ status_t OMXNodeInstance::configureVideoTunnelMode(
status_t OMXNodeInstance::useBuffer(
OMX_U32 portIndex, const sp<IMemory> &params,
- OMX::buffer_id *buffer) {
+ OMX::buffer_id *buffer, OMX_U32 allottedSize) {
Mutex::Autolock autoLock(mLock);
+ if (allottedSize > params->size()) {
+ return BAD_VALUE;
+ }
BufferMeta *buffer_meta = new BufferMeta(params);
@@ -629,10 +632,11 @@ status_t OMXNodeInstance::useBuffer(
OMX_ERRORTYPE err = OMX_UseBuffer(
mHandle, &header, portIndex, buffer_meta,
- params->size(), static_cast<OMX_U8 *>(params->pointer()));
+ allottedSize, static_cast<OMX_U8 *>(params->pointer()));
if (err != OMX_ErrorNone) {
- CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(portIndex, params->size(), params->pointer()));
+ CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(
+ portIndex, (size_t)allottedSize, params->pointer()));
delete buffer_meta;
buffer_meta = NULL;
@@ -654,7 +658,7 @@ status_t OMXNodeInstance::useBuffer(
}
CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT(
- *buffer, portIndex, "%zu@%p", params->size(), params->pointer()));
+ *buffer, portIndex, "%u@%p", allottedSize, params->pointer()));
return OK;
}
@@ -939,19 +943,21 @@ status_t OMXNodeInstance::allocateBuffer(
status_t OMXNodeInstance::allocateBufferWithBackup(
OMX_U32 portIndex, const sp<IMemory> &params,
- OMX::buffer_id *buffer) {
+ OMX::buffer_id *buffer, OMX_U32 allottedSize) {
Mutex::Autolock autoLock(mLock);
+ if (allottedSize > params->size()) {
+ return BAD_VALUE;
+ }
BufferMeta *buffer_meta = new BufferMeta(params, true);
OMX_BUFFERHEADERTYPE *header;
OMX_ERRORTYPE err = OMX_AllocateBuffer(
- mHandle, &header, portIndex, buffer_meta, params->size());
-
+ mHandle, &header, portIndex, buffer_meta, allottedSize);
if (err != OMX_ErrorNone) {
CLOG_ERROR(allocateBufferWithBackup, err,
- SIMPLE_BUFFER(portIndex, params->size(), params->pointer()));
+ SIMPLE_BUFFER(portIndex, (size_t)allottedSize, params->pointer()));
delete buffer_meta;
buffer_meta = NULL;
@@ -971,8 +977,8 @@ status_t OMXNodeInstance::allocateBufferWithBackup(
bufferSource->addCodecBuffer(header);
}
- CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p :> %p",
- params->size(), params->pointer(), header->pBuffer));
+ CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%u@%p :> %p",
+ allottedSize, params->pointer(), header->pBuffer));
return OK;
}
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 67ff145..294b2ed 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -193,7 +193,7 @@ status_t Harness::allocatePortBuffers(
CHECK(buffer.mMemory != NULL);
err = mOMX->allocateBufferWithBackup(
- node, portIndex, buffer.mMemory, &buffer.mID);
+ node, portIndex, buffer.mMemory, &buffer.mID, buffer.mMemory->size());
EXPECT_SUCCESS(err, "allocateBuffer");
buffers->push(buffer);
diff --git a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
index cee62a3..ab547be 100644
--- a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
+++ b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
@@ -150,7 +150,11 @@ TEST_F(MediaCodecListOverridesTest, exportTestResultsToXML) {
fclose(f);
free(buf);
- EXPECT_TRUE(overrides == kTestOverridesStr);
+ AString expected;
+ expected.append(getProfilingVersionString());
+ expected.append("\n");
+ expected.append(kTestOverridesStr);
+ EXPECT_TRUE(overrides == expected);
remove(fileName);
}
diff --git a/media/utils/Android.mk b/media/utils/Android.mk
new file mode 100644
index 0000000..dfadbc8
--- /dev/null
+++ b/media/utils/Android.mk
@@ -0,0 +1,39 @@
+# Copyright 2015 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 $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ BatteryNotifier.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libcutils \
+ liblog \
+ libutils \
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+LOCAL_CFLAGS += \
+ -Wall \
+ -Wextra \
+ -Werror \
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+
+LOCAL_MODULE := libmediautils
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/utils/BatteryNotifier.cpp b/media/utils/BatteryNotifier.cpp
new file mode 100644
index 0000000..7f9cd7a
--- /dev/null
+++ b/media/utils/BatteryNotifier.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2015, 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.
+ */
+
+#include "include/mediautils/BatteryNotifier.h"
+
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+void BatteryNotifier::DeathNotifier::binderDied(const wp<IBinder>& /*who*/) {
+ BatteryNotifier::getInstance().onBatteryStatServiceDied();
+}
+
+BatteryNotifier::BatteryNotifier() : mVideoRefCount(0), mAudioRefCount(0) {}
+
+BatteryNotifier::~BatteryNotifier() {
+ Mutex::Autolock _l(mLock);
+ if (mDeathNotifier != nullptr) {
+ IInterface::asBinder(mBatteryStatService)->unlinkToDeath(mDeathNotifier);
+ }
+}
+
+void BatteryNotifier::noteStartVideo() {
+ Mutex::Autolock _l(mLock);
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+ if (mVideoRefCount == 0 && batteryService != nullptr) {
+ batteryService->noteStartVideo(AID_MEDIA);
+ }
+ mVideoRefCount++;
+}
+
+void BatteryNotifier::noteStopVideo() {
+ Mutex::Autolock _l(mLock);
+ if (mVideoRefCount == 0) {
+ ALOGW("%s: video refcount is broken.", __FUNCTION__);
+ return;
+ }
+
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+
+ mVideoRefCount--;
+ if (mVideoRefCount == 0 && batteryService != nullptr) {
+ batteryService->noteStopVideo(AID_MEDIA);
+ }
+}
+
+void BatteryNotifier::noteResetVideo() {
+ Mutex::Autolock _l(mLock);
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+ mVideoRefCount = 0;
+ if (batteryService != nullptr) {
+ batteryService->noteResetAudio();
+ }
+}
+
+void BatteryNotifier::noteStartAudio() {
+ Mutex::Autolock _l(mLock);
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+ if (mAudioRefCount == 0 && batteryService != nullptr) {
+ batteryService->noteStartAudio(AID_MEDIA);
+ }
+ mAudioRefCount++;
+}
+
+void BatteryNotifier::noteStopAudio() {
+ Mutex::Autolock _l(mLock);
+ if (mAudioRefCount == 0) {
+ ALOGW("%s: audio refcount is broken.", __FUNCTION__);
+ return;
+ }
+
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+
+ mAudioRefCount--;
+ if (mAudioRefCount == 0 && batteryService != nullptr) {
+ batteryService->noteStopAudio(AID_MEDIA);
+ }
+}
+
+void BatteryNotifier::noteResetAudio() {
+ Mutex::Autolock _l(mLock);
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+ mAudioRefCount = 0;
+ if (batteryService != nullptr) {
+ batteryService->noteResetAudio();
+ }
+}
+
+void BatteryNotifier::noteFlashlightOn(const String8& id, int uid) {
+ Mutex::Autolock _l(mLock);
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+
+ std::pair<String8, int> k = std::make_pair(id, uid);
+ if (!mFlashlightState[k]) {
+ mFlashlightState[k] = true;
+ if (batteryService != nullptr) {
+ batteryService->noteFlashlightOn(uid);
+ }
+ }
+}
+
+void BatteryNotifier::noteFlashlightOff(const String8& id, int uid) {
+ Mutex::Autolock _l(mLock);
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+
+ std::pair<String8, int> k = std::make_pair(id, uid);
+ if (mFlashlightState[k]) {
+ mFlashlightState[k] = false;
+ if (batteryService != nullptr) {
+ batteryService->noteFlashlightOff(uid);
+ }
+ }
+}
+
+void BatteryNotifier::noteResetFlashlight() {
+ Mutex::Autolock _l(mLock);
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+ mFlashlightState.clear();
+ if (batteryService != nullptr) {
+ batteryService->noteResetFlashlight();
+ }
+}
+
+void BatteryNotifier::noteStartCamera(const String8& id, int uid) {
+ Mutex::Autolock _l(mLock);
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+ std::pair<String8, int> k = std::make_pair(id, uid);
+ if (!mCameraState[k]) {
+ mCameraState[k] = true;
+ if (batteryService != nullptr) {
+ batteryService->noteStartCamera(uid);
+ }
+ }
+}
+
+void BatteryNotifier::noteStopCamera(const String8& id, int uid) {
+ Mutex::Autolock _l(mLock);
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+ std::pair<String8, int> k = std::make_pair(id, uid);
+ if (mCameraState[k]) {
+ mCameraState[k] = false;
+ if (batteryService != nullptr) {
+ batteryService->noteStopCamera(uid);
+ }
+ }
+}
+
+void BatteryNotifier::noteResetCamera() {
+ Mutex::Autolock _l(mLock);
+ sp<IBatteryStats> batteryService = getBatteryService_l();
+ mCameraState.clear();
+ if (batteryService != nullptr) {
+ batteryService->noteResetCamera();
+ }
+}
+
+void BatteryNotifier::onBatteryStatServiceDied() {
+ Mutex::Autolock _l(mLock);
+ mBatteryStatService.clear();
+ mDeathNotifier.clear();
+ // Do not reset mVideoRefCount and mAudioRefCount here. The ref
+ // counting is independent of the battery service availability.
+ // We need this if battery service becomes available after media
+ // started.
+
+}
+
+sp<IBatteryStats> BatteryNotifier::getBatteryService_l() {
+ if (mBatteryStatService != nullptr) {
+ return mBatteryStatService;
+ }
+ // Get battery service from service manager
+ const sp<IServiceManager> sm(defaultServiceManager());
+ if (sm != nullptr) {
+ const String16 name("batterystats");
+ mBatteryStatService = interface_cast<IBatteryStats>(sm->checkService(name));
+ if (mBatteryStatService == nullptr) {
+ ALOGE("batterystats service unavailable!");
+ return nullptr;
+ }
+
+ mDeathNotifier = new DeathNotifier();
+ IInterface::asBinder(mBatteryStatService)->linkToDeath(mDeathNotifier);
+
+ // Notify start now if media already started
+ if (mVideoRefCount > 0) {
+ mBatteryStatService->noteStartVideo(AID_MEDIA);
+ }
+ if (mAudioRefCount > 0) {
+ mBatteryStatService->noteStartAudio(AID_MEDIA);
+ }
+ }
+ return mBatteryStatService;
+}
+
+ANDROID_SINGLETON_STATIC_INSTANCE(BatteryNotifier);
+
+} // namespace android
diff --git a/media/utils/README b/media/utils/README
new file mode 100644
index 0000000..65ab0b8
--- /dev/null
+++ b/media/utils/README
@@ -0,0 +1,4 @@
+This is a common shared library for media utility classes.
+
+Consider adding your utility class/function here if it will
+be used across several of the media libraries.
diff --git a/media/utils/include/mediautils/BatteryNotifier.h b/media/utils/include/mediautils/BatteryNotifier.h
new file mode 100644
index 0000000..4904804
--- /dev/null
+++ b/media/utils/include/mediautils/BatteryNotifier.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015, 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 MEDIA_BATTERY_NOTIFIER_H
+#define MEDIA_BATTERY_NOTIFIER_H
+
+#include <binder/IBatteryStats.h>
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+#include <map>
+#include <utility>
+
+namespace android {
+
+/**
+ * Class used for logging battery life events in mediaserver.
+ */
+class BatteryNotifier : public Singleton<BatteryNotifier> {
+
+ friend class Singleton<BatteryNotifier>;
+ BatteryNotifier();
+
+public:
+ ~BatteryNotifier();
+
+ void noteStartVideo();
+ void noteStopVideo();
+ void noteResetVideo();
+ void noteStartAudio();
+ void noteStopAudio();
+ void noteResetAudio();
+ void noteFlashlightOn(const String8& id, int uid);
+ void noteFlashlightOff(const String8& id, int uid);
+ void noteResetFlashlight();
+ void noteStartCamera(const String8& id, int uid);
+ void noteStopCamera(const String8& id, int uid);
+ void noteResetCamera();
+
+private:
+ void onBatteryStatServiceDied();
+
+ class DeathNotifier : public IBinder::DeathRecipient {
+ virtual void binderDied(const wp<IBinder>& /*who*/);
+ };
+
+ Mutex mLock;
+ int mVideoRefCount;
+ int mAudioRefCount;
+ std::map<std::pair<String8, int>, bool> mFlashlightState;
+ std::map<std::pair<String8, int>, bool> mCameraState;
+ sp<IBatteryStats> mBatteryStatService;
+ sp<DeathNotifier> mDeathNotifier;
+
+ sp<IBatteryStats> getBatteryService_l();
+};
+
+} // namespace android
+
+#endif // MEDIA_BATTERY_NOTIFIER_H
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 9c60911..cbead32 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -62,6 +62,7 @@ LOCAL_SHARED_LIBRARIES:= \
libbinder \
libcutils \
libmedia \
+ libmediautils \
libcamera_client \
libgui \
libhardware \
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 79e73f9..6f073ed 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -41,6 +41,7 @@
#include <media/AudioSystem.h>
#include <media/IMediaHTTPService.h>
#include <media/mediaplayer.h>
+#include <mediautils/BatteryNotifier.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/String16.h>
@@ -140,6 +141,11 @@ void CameraService::onFirstRef()
BnCameraService::onFirstRef();
+ // Update battery life tracking if service is restarting
+ BatteryNotifier& notifier(BatteryNotifier::getInstance());
+ notifier.noteResetCamera();
+ notifier.noteResetFlashlight();
+
camera_module_t *rawModule;
int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
(const hw_module_t **)&rawModule);
@@ -336,12 +342,39 @@ void CameraService::onTorchStatusChangedLocked(const String8& cameraId,
res = setTorchStatusLocked(cameraId, newStatus);
if (res) {
- ALOGE("%s: Failed to set the torch status", __FUNCTION__,
- (uint32_t)newStatus);
+ ALOGE("%s: Failed to set the torch status", __FUNCTION__, (uint32_t)newStatus);
return;
}
{
+ // Update battery life logging for flashlight
+ Mutex::Autolock al(mTorchClientMapMutex);
+ auto iter = mTorchUidMap.find(cameraId);
+ if (iter != mTorchUidMap.end()) {
+ int oldUid = iter->second.second;
+ int newUid = iter->second.first;
+ BatteryNotifier& notifier(BatteryNotifier::getInstance());
+ if (oldUid != newUid) {
+ // If the UID has changed, log the status and update current UID in mTorchUidMap
+ if (status == ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON) {
+ notifier.noteFlashlightOff(cameraId, oldUid);
+ }
+ if (newStatus == ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON) {
+ notifier.noteFlashlightOn(cameraId, newUid);
+ }
+ iter->second.second = newUid;
+ } else {
+ // If the UID has not changed, log the status
+ if (newStatus == ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON) {
+ notifier.noteFlashlightOn(cameraId, oldUid);
+ } else {
+ notifier.noteFlashlightOff(cameraId, oldUid);
+ }
+ }
+ }
+ }
+
+ {
Mutex::Autolock lock(mStatusListenerLock);
for (auto& i : mListenerList) {
i->onTorchStatusChanged(newStatus, String16{cameraId});
@@ -1154,12 +1187,13 @@ status_t CameraService::connectDevice(
status_t CameraService::setTorchMode(const String16& cameraId, bool enabled,
const sp<IBinder>& clientBinder) {
- if (enabled && clientBinder == NULL) {
+ if (enabled && clientBinder == nullptr) {
ALOGE("%s: torch client binder is NULL", __FUNCTION__);
return -EINVAL;
}
String8 id = String8(cameraId.string());
+ int uid = getCallingUid();
// verify id is valid.
auto state = getCameraState(id);
@@ -1198,7 +1232,21 @@ status_t CameraService::setTorchMode(const String16& cameraId, bool enabled,
}
}
+ {
+ // Update UID map - this is used in the torch status changed callbacks, so must be done
+ // before setTorchMode
+ Mutex::Autolock al(mTorchClientMapMutex);
+ if (mTorchUidMap.find(id) == mTorchUidMap.end()) {
+ mTorchUidMap[id].first = uid;
+ mTorchUidMap[id].second = uid;
+ } else {
+ // Set the pending UID
+ mTorchUidMap[id].first = uid;
+ }
+ }
+
status_t res = mFlashlight->setTorchMode(id, enabled);
+
if (res) {
ALOGE("%s: setting torch mode of camera %s to %d failed. %s (%d)",
__FUNCTION__, id.string(), enabled, strerror(-res), res);
@@ -1209,19 +1257,17 @@ status_t CameraService::setTorchMode(const String16& cameraId, bool enabled,
// update the link to client's death
Mutex::Autolock al(mTorchClientMapMutex);
ssize_t index = mTorchClientMap.indexOfKey(id);
+ BatteryNotifier& notifier(BatteryNotifier::getInstance());
if (enabled) {
if (index == NAME_NOT_FOUND) {
mTorchClientMap.add(id, clientBinder);
} else {
- const sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
- oldBinder->unlinkToDeath(this);
-
+ mTorchClientMap.valueAt(index)->unlinkToDeath(this);
mTorchClientMap.replaceValueAt(index, clientBinder);
}
clientBinder->linkToDeath(this);
} else if (index != NAME_NOT_FOUND) {
- sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
- oldBinder->unlinkToDeath(this);
+ mTorchClientMap.valueAt(index)->unlinkToDeath(this);
}
}
@@ -1243,8 +1289,7 @@ void CameraService::notifySystemEvent(int32_t eventId, const int32_t* args, size
}
}
-status_t CameraService::addListener(
- const sp<ICameraServiceListener>& listener) {
+status_t CameraService::addListener(const sp<ICameraServiceListener>& listener) {
ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
if (listener == 0) {
@@ -1965,9 +2010,40 @@ String8 CameraService::CameraState::getId() const {
}
// ----------------------------------------------------------------------------
+// ClientEventListener
+// ----------------------------------------------------------------------------
+
+void CameraService::ClientEventListener::onClientAdded(
+ const resource_policy::ClientDescriptor<String8,
+ sp<CameraService::BasicClient>>& descriptor) {
+ auto basicClient = descriptor.getValue();
+ if (basicClient.get() != nullptr) {
+ BatteryNotifier& notifier(BatteryNotifier::getInstance());
+ notifier.noteStartCamera(descriptor.getKey(),
+ static_cast<int>(basicClient->getClientUid()));
+ }
+}
+
+void CameraService::ClientEventListener::onClientRemoved(
+ const resource_policy::ClientDescriptor<String8,
+ sp<CameraService::BasicClient>>& descriptor) {
+ auto basicClient = descriptor.getValue();
+ if (basicClient.get() != nullptr) {
+ BatteryNotifier& notifier(BatteryNotifier::getInstance());
+ notifier.noteStopCamera(descriptor.getKey(),
+ static_cast<int>(basicClient->getClientUid()));
+ }
+}
+
+
+// ----------------------------------------------------------------------------
// CameraClientManager
// ----------------------------------------------------------------------------
+CameraService::CameraClientManager::CameraClientManager() {
+ setListener(std::make_shared<ClientEventListener>());
+}
+
CameraService::CameraClientManager::~CameraClientManager() {}
sp<CameraService::BasicClient> CameraService::CameraClientManager::getCameraClient(
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index ce3cb44..3298772 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -46,6 +46,7 @@
#include <string>
#include <map>
#include <memory>
+#include <utility>
namespace android {
@@ -327,6 +328,20 @@ public:
}; // class Client
+ /**
+ * A listener class that implements the LISTENER interface for use with a ClientManager, and
+ * implements the following methods:
+ * void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
+ * void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
+ */
+ class ClientEventListener {
+ public:
+ void onClientAdded(const resource_policy::ClientDescriptor<String8,
+ sp<CameraService::BasicClient>>& descriptor);
+ void onClientRemoved(const resource_policy::ClientDescriptor<String8,
+ sp<CameraService::BasicClient>>& descriptor);
+ }; // class ClientEventListener
+
typedef std::shared_ptr<resource_policy::ClientDescriptor<String8,
sp<CameraService::BasicClient>>> DescriptorPtr;
@@ -338,9 +353,10 @@ public:
* This class manages the eviction behavior for the camera clients. See the parent class
* implementation in utils/ClientManager for the specifics of this behavior.
*/
- class CameraClientManager :
- public resource_policy::ClientManager<String8, sp<CameraService::BasicClient>> {
+ class CameraClientManager : public resource_policy::ClientManager<String8,
+ sp<CameraService::BasicClient>, ClientEventListener> {
public:
+ CameraClientManager();
virtual ~CameraClientManager();
/**
@@ -624,13 +640,15 @@ private:
sp<CameraFlashlight> mFlashlight;
// guard mTorchStatusMap
Mutex mTorchStatusMutex;
- // guard mTorchClientMap
+ // guard mTorchClientMap, mTorchUidMap
Mutex mTorchClientMapMutex;
// camera id -> torch status
KeyedVector<String8, ICameraServiceListener::TorchStatus> mTorchStatusMap;
// camera id -> torch client binder
// only store the last client that turns on each camera's torch mode
- KeyedVector<String8, sp<IBinder> > mTorchClientMap;
+ KeyedVector<String8, sp<IBinder>> mTorchClientMap;
+ // camera id -> [incoming uid, current uid] pair
+ std::map<String8, std::pair<int, int>> mTorchUidMap;
// check and handle if torch client's process has died
void handleTorchClientBinderDied(const wp<IBinder> &who);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 0bc8ed1..45d9421 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2613,6 +2613,21 @@ status_t Camera3Device::RequestThread::clear(
if (listener != NULL) {
for (RequestList::iterator it = mRequestQueue.begin();
it != mRequestQueue.end(); ++it) {
+ // Abort the input buffers for reprocess requests.
+ if ((*it)->mInputStream != NULL) {
+ camera3_stream_buffer_t inputBuffer;
+ status_t res = (*it)->mInputStream->getInputBuffer(&inputBuffer);
+ if (res != OK) {
+ ALOGW("%s: %d: couldn't get input buffer while clearing the request "
+ "list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res);
+ } else {
+ res = (*it)->mInputStream->returnInputBuffer(inputBuffer);
+ if (res != OK) {
+ ALOGE("%s: %d: couldn't return input buffer while clearing the request "
+ "list: %s (%d)", __FUNCTION__, __LINE__, strerror(-res), res);
+ }
+ }
+ }
// Set the frame number this request would have had, if it
// had been submitted; this frame number will not be reused.
// The requestId and burstId fields were set when the request was
@@ -2752,31 +2767,11 @@ bool Camera3Device::RequestThread::threadLoop() {
__FUNCTION__);
}
- camera3_stream_buffer_t inputBuffer;
uint32_t totalNumBuffers = 0;
// Fill in buffers
-
if (nextRequest->mInputStream != NULL) {
- res = nextRequest->mInputStream->getInputBuffer(&inputBuffer);
- if (res != OK) {
- // Can't get input buffer from gralloc queue - this could be due to
- // disconnected queue or other producer misbehavior, so not a fatal
- // error
- ALOGE("RequestThread: Can't get input buffer, skipping request:"
- " %s (%d)", strerror(-res), res);
- {
- Mutex::Autolock l(mRequestLock);
- if (mListener != NULL) {
- mListener->notifyError(
- ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
- nextRequest->mResultExtras);
- }
- }
- cleanUpFailedRequest(request, nextRequest, outputBuffers);
- return true;
- }
- request.input_buffer = &inputBuffer;
+ request.input_buffer = &nextRequest->mInputBuffer;
totalNumBuffers += 1;
} else {
request.input_buffer = NULL;
@@ -2932,9 +2927,9 @@ void Camera3Device::RequestThread::cleanUpFailedRequest(
if (request.settings != NULL) {
nextRequest->mSettings.unlock(request.settings);
}
- if (request.input_buffer != NULL) {
- request.input_buffer->status = CAMERA3_BUFFER_STATUS_ERROR;
- nextRequest->mInputStream->returnInputBuffer(*(request.input_buffer));
+ if (nextRequest->mInputStream != NULL) {
+ nextRequest->mInputBuffer.status = CAMERA3_BUFFER_STATUS_ERROR;
+ nextRequest->mInputStream->returnInputBuffer(nextRequest->mInputBuffer);
}
for (size_t i = 0; i < request.num_output_buffers; i++) {
outputBuffers.editItemAt(i).status = CAMERA3_BUFFER_STATUS_ERROR;
@@ -3026,6 +3021,25 @@ sp<Camera3Device::CaptureRequest>
nextRequest->mResultExtras.frameNumber = mFrameNumber++;
nextRequest->mResultExtras.afTriggerId = mCurrentAfTriggerId;
nextRequest->mResultExtras.precaptureTriggerId = mCurrentPreCaptureTriggerId;
+
+ // Since RequestThread::clear() removes buffers from the input stream,
+ // get the right buffer here before unlocking mRequestLock
+ if (nextRequest->mInputStream != NULL) {
+ res = nextRequest->mInputStream->getInputBuffer(&nextRequest->mInputBuffer);
+ if (res != OK) {
+ // Can't get input buffer from gralloc queue - this could be due to
+ // disconnected queue or other producer misbehavior, so not a fatal
+ // error
+ ALOGE("%s: Can't get input buffer, skipping request:"
+ " %s (%d)", __FUNCTION__, strerror(-res), res);
+ if (mListener != NULL) {
+ mListener->notifyError(
+ ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST,
+ nextRequest->mResultExtras);
+ }
+ return NULL;
+ }
+ }
}
mNextRequest = nextRequest;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index fcb5180..b9313fc 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -234,6 +234,7 @@ class Camera3Device :
public:
CameraMetadata mSettings;
sp<camera3::Camera3Stream> mInputStream;
+ camera3_stream_buffer_t mInputBuffer;
Vector<sp<camera3::Camera3OutputStreamInterface> >
mOutputStreams;
CaptureResultExtras mResultExtras;
diff --git a/services/camera/libcameraservice/utils/ClientManager.h b/services/camera/libcameraservice/utils/ClientManager.h
index 5afb7a3..7ae58d5 100644
--- a/services/camera/libcameraservice/utils/ClientManager.h
+++ b/services/camera/libcameraservice/utils/ClientManager.h
@@ -172,6 +172,26 @@ void ClientDescriptor<KEY, VALUE>::setPriority(int32_t priority) {
// --------------------------------------------------------------------------------
/**
+ * A default class implementing the LISTENER interface used by ClientManager.
+ */
+template<class KEY, class VALUE>
+class DefaultEventListener {
+public:
+ void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
+ void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
+};
+
+template<class KEY, class VALUE>
+void DefaultEventListener<KEY, VALUE>::onClientAdded(
+ const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
+
+template<class KEY, class VALUE>
+void DefaultEventListener<KEY, VALUE>::onClientRemoved(
+ const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {}
+
+// --------------------------------------------------------------------------------
+
+/**
* The ClientManager class wraps an LRU-ordered list of active clients and implements eviction
* behavior for handling shared resource access.
*
@@ -189,7 +209,7 @@ void ClientDescriptor<KEY, VALUE>::setPriority(int32_t priority) {
* incoming descriptor has the highest priority. Otherwise, the incoming descriptor is
* removed instead.
*/
-template<class KEY, class VALUE>
+template<class KEY, class VALUE, class LISTENER=DefaultEventListener<KEY, VALUE>>
class ClientManager {
public:
// The default maximum "cost" allowed before evicting
@@ -275,6 +295,24 @@ public:
status_t waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
nsecs_t timeout) const;
+ /**
+ * Set the current listener for client add/remove events.
+ *
+ * The listener instance must inherit from the LISTENER class and implement the following
+ * methods:
+ * void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor);
+ * void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor);
+ *
+ * These callback methods will be called with the ClientManager's lock held, and should
+ * not call any further ClientManager methods.
+ *
+ * The onClientRemoved method will be called when the client has been removed or evicted
+ * from the ClientManager that this event listener has been added to. The onClientAdded
+ * method will be called when the client has been added to the ClientManager that this
+ * event listener has been added to.
+ */
+ void setListener(const std::shared_ptr<LISTENER>& listener);
+
protected:
~ClientManager();
@@ -300,36 +338,38 @@ private:
int32_t mMaxCost;
// LRU ordered, most recent at end
std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> mClients;
+ std::shared_ptr<LISTENER> mListener;
}; // class ClientManager
-template<class KEY, class VALUE>
-ClientManager<KEY, VALUE>::ClientManager() :
+template<class KEY, class VALUE, class LISTENER>
+ClientManager<KEY, VALUE, LISTENER>::ClientManager() :
ClientManager(DEFAULT_MAX_COST) {}
-template<class KEY, class VALUE>
-ClientManager<KEY, VALUE>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {}
+template<class KEY, class VALUE, class LISTENER>
+ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {}
-template<class KEY, class VALUE>
-ClientManager<KEY, VALUE>::~ClientManager() {}
+template<class KEY, class VALUE, class LISTENER>
+ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {}
-template<class KEY, class VALUE>
-std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> ClientManager<KEY, VALUE>::wouldEvict(
+template<class KEY, class VALUE, class LISTENER>
+std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
+ClientManager<KEY, VALUE, LISTENER>::wouldEvict(
const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
Mutex::Autolock lock(mLock);
return wouldEvictLocked(client);
}
-template<class KEY, class VALUE>
+template<class KEY, class VALUE, class LISTENER>
std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
-ClientManager<KEY, VALUE>::getIncompatibleClients(
+ClientManager<KEY, VALUE, LISTENER>::getIncompatibleClients(
const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const {
Mutex::Autolock lock(mLock);
return wouldEvictLocked(client, /*returnIncompatibleClients*/true);
}
-template<class KEY, class VALUE>
+template<class KEY, class VALUE, class LISTENER>
std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
-ClientManager<KEY, VALUE>::wouldEvictLocked(
+ClientManager<KEY, VALUE, LISTENER>::wouldEvictLocked(
const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client,
bool returnIncompatibleClients) const {
@@ -420,8 +460,9 @@ ClientManager<KEY, VALUE>::wouldEvictLocked(
}
-template<class KEY, class VALUE>
-std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> ClientManager<KEY, VALUE>::addAndEvict(
+template<class KEY, class VALUE, class LISTENER>
+std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
+ClientManager<KEY, VALUE, LISTENER>::addAndEvict(
const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) {
Mutex::Autolock lock(mLock);
auto evicted = wouldEvictLocked(client);
@@ -433,6 +474,9 @@ std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> ClientManager<KEY, VA
auto iter = evicted.cbegin();
if (iter != evicted.cend()) {
+
+ if (mListener != nullptr) mListener->onClientRemoved(**iter);
+
// Remove evicted clients from list
mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
[&iter] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
@@ -444,21 +488,22 @@ std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> ClientManager<KEY, VA
}), mClients.end());
}
+ if (mListener != nullptr) mListener->onClientAdded(*client);
mClients.push_back(client);
mRemovedCondition.broadcast();
return evicted;
}
-template<class KEY, class VALUE>
+template<class KEY, class VALUE, class LISTENER>
std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>>
-ClientManager<KEY, VALUE>::getAll() const {
+ClientManager<KEY, VALUE, LISTENER>::getAll() const {
Mutex::Autolock lock(mLock);
return mClients;
}
-template<class KEY, class VALUE>
-std::vector<KEY> ClientManager<KEY, VALUE>::getAllKeys() const {
+template<class KEY, class VALUE, class LISTENER>
+std::vector<KEY> ClientManager<KEY, VALUE, LISTENER>::getAllKeys() const {
Mutex::Autolock lock(mLock);
std::vector<KEY> keys(mClients.size());
for (const auto& i : mClients) {
@@ -467,8 +512,8 @@ std::vector<KEY> ClientManager<KEY, VALUE>::getAllKeys() const {
return keys;
}
-template<class KEY, class VALUE>
-std::vector<int32_t> ClientManager<KEY, VALUE>::getAllOwners() const {
+template<class KEY, class VALUE, class LISTENER>
+std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const {
Mutex::Autolock lock(mLock);
std::set<int32_t> owners;
for (const auto& i : mClients) {
@@ -477,8 +522,8 @@ std::vector<int32_t> ClientManager<KEY, VALUE>::getAllOwners() const {
return std::vector<int32_t>(owners.begin(), owners.end());
}
-template<class KEY, class VALUE>
-void ClientManager<KEY, VALUE>::updatePriorities(
+template<class KEY, class VALUE, class LISTENER>
+void ClientManager<KEY, VALUE, LISTENER>::updatePriorities(
const std::map<int32_t,int32_t>& ownerPriorityList) {
Mutex::Autolock lock(mLock);
for (auto& i : mClients) {
@@ -489,8 +534,8 @@ void ClientManager<KEY, VALUE>::updatePriorities(
}
}
-template<class KEY, class VALUE>
-std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE>::get(
+template<class KEY, class VALUE, class LISTENER>
+std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::get(
const KEY& key) const {
Mutex::Autolock lock(mLock);
for (const auto& i : mClients) {
@@ -499,23 +544,30 @@ std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE>::get(
return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr);
}
-template<class KEY, class VALUE>
-void ClientManager<KEY, VALUE>::removeAll() {
+template<class KEY, class VALUE, class LISTENER>
+void ClientManager<KEY, VALUE, LISTENER>::removeAll() {
Mutex::Autolock lock(mLock);
+ if (mListener != nullptr) {
+ for (const auto& i : mClients) {
+ mListener->onClientRemoved(*i);
+ }
+ }
mClients.clear();
mRemovedCondition.broadcast();
}
-template<class KEY, class VALUE>
-std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE>::remove(const KEY& key) {
+template<class KEY, class VALUE, class LISTENER>
+std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove(
+ const KEY& key) {
Mutex::Autolock lock(mLock);
std::shared_ptr<ClientDescriptor<KEY, VALUE>> ret;
// Remove evicted clients from list
mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
- [&key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
+ [this, &key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
if (curClientPtr->getKey() == key) {
+ if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
ret = curClientPtr;
return true;
}
@@ -526,8 +578,8 @@ std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE>::remove(
return ret;
}
-template<class KEY, class VALUE>
-status_t ClientManager<KEY, VALUE>::waitUntilRemoved(
+template<class KEY, class VALUE, class LISTENER>
+status_t ClientManager<KEY, VALUE, LISTENER>::waitUntilRemoved(
const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client,
nsecs_t timeout) const {
status_t ret = NO_ERROR;
@@ -558,14 +610,21 @@ status_t ClientManager<KEY, VALUE>::waitUntilRemoved(
return ret;
}
-template<class KEY, class VALUE>
-void ClientManager<KEY, VALUE>::remove(
+template<class KEY, class VALUE, class LISTENER>
+void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) {
+ Mutex::Autolock lock(mLock);
+ mListener = listener;
+}
+
+template<class KEY, class VALUE, class LISTENER>
+void ClientManager<KEY, VALUE, LISTENER>::remove(
const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value) {
Mutex::Autolock lock(mLock);
// Remove evicted clients from list
mClients.erase(std::remove_if(mClients.begin(), mClients.end(),
- [&value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
+ [this, &value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) {
if (curClientPtr == value) {
+ if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr);
return true;
}
return false;
@@ -573,8 +632,8 @@ void ClientManager<KEY, VALUE>::remove(
mRemovedCondition.broadcast();
}
-template<class KEY, class VALUE>
-int64_t ClientManager<KEY, VALUE>::getCurrentCostLocked() const {
+template<class KEY, class VALUE, class LISTENER>
+int64_t ClientManager<KEY, VALUE, LISTENER>::getCurrentCostLocked() const {
int64_t totalCost = 0;
for (const auto& x : mClients) {
totalCost += x->getCost();