Camera: Pass system health metrics to ServiceProxy
- Measure session statistics:
- Camera open, close, and session creation latency
- Session information such as camera id, is_ndk, operating mode,
and reconfiguration count.
- Measure stream statistics:
- width, height, format, dataspace, usage
- max buffer count
- buffer loss count
- startup latency.
Test: ./out/host/linux-x86/bin/statsd_testdrive 227
Test: Camera CTS, VNDK test
Bug: 154159000
Change-Id: I082ef26a312bddbfd4abcc2148728a4b7bf8a9f6
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
new file mode 100644
index 0000000..0557fcc
--- /dev/null
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2020 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 "CameraServiceProxyWrapper"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <inttypes.h>
+#include <utils/Log.h>
+#include <binder/IServiceManager.h>
+
+#include "CameraServiceProxyWrapper.h"
+
+namespace android {
+
+using hardware::ICameraServiceProxy;
+using hardware::CameraSessionStats;
+
+Mutex CameraServiceProxyWrapper::sProxyMutex;
+sp<hardware::ICameraServiceProxy> CameraServiceProxyWrapper::sCameraServiceProxy;
+
+Mutex CameraServiceProxyWrapper::mLock;
+std::map<String8, std::shared_ptr<CameraServiceProxyWrapper::CameraSessionStatsWrapper>>
+ CameraServiceProxyWrapper::mSessionStatsMap;
+
+/**
+ * CameraSessionStatsWrapper functions
+ */
+
+void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onOpen() {
+ Mutex::Autolock l(mLock);
+
+ updateProxyDeviceState(mSessionStats);
+}
+
+void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onClose(int32_t latencyMs) {
+ Mutex::Autolock l(mLock);
+
+ mSessionStats.mNewCameraState = CameraSessionStats::CAMERA_STATE_CLOSED;
+ mSessionStats.mLatencyMs = latencyMs;
+ updateProxyDeviceState(mSessionStats);
+}
+
+void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onStreamConfigured(
+ int operatingMode, bool internalReconfig, int32_t latencyMs) {
+ Mutex::Autolock l(mLock);
+
+ if (internalReconfig) {
+ mSessionStats.mInternalReconfigure++;
+ } else {
+ mSessionStats.mLatencyMs = latencyMs;
+ mSessionStats.mSessionType = operatingMode;
+ }
+}
+
+void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onActive() {
+ Mutex::Autolock l(mLock);
+
+ mSessionStats.mNewCameraState = CameraSessionStats::CAMERA_STATE_ACTIVE;
+ updateProxyDeviceState(mSessionStats);
+
+ // Reset mCreationDuration to -1 to distinguish between 1st session
+ // after configuration, and all other sessions after configuration.
+ mSessionStats.mLatencyMs = -1;
+}
+
+void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onIdle(
+ int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+ const std::vector<hardware::CameraStreamStats>& streamStats) {
+ Mutex::Autolock l(mLock);
+
+ mSessionStats.mNewCameraState = CameraSessionStats::CAMERA_STATE_IDLE;
+ mSessionStats.mRequestCount = requestCount;
+ mSessionStats.mResultErrorCount = resultErrorCount;
+ mSessionStats.mDeviceError = deviceError;
+ mSessionStats.mStreamStats = streamStats;
+ updateProxyDeviceState(mSessionStats);
+
+ mSessionStats.mInternalReconfigure = 0;
+ mSessionStats.mStreamStats.clear();
+}
+
+/**
+ * CameraServiceProxyWrapper functions
+ */
+
+sp<ICameraServiceProxy> CameraServiceProxyWrapper::getCameraServiceProxy() {
+#ifndef __BRILLO__
+ Mutex::Autolock al(sProxyMutex);
+ if (sCameraServiceProxy == nullptr) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ // Use checkService because cameraserver normally starts before the
+ // system server and the proxy service. So the long timeout that getService
+ // has before giving up is inappropriate.
+ sp<IBinder> binder = sm->checkService(String16("media.camera.proxy"));
+ if (binder != nullptr) {
+ sCameraServiceProxy = interface_cast<ICameraServiceProxy>(binder);
+ }
+ }
+#endif
+ return sCameraServiceProxy;
+}
+
+void CameraServiceProxyWrapper::pingCameraServiceProxy() {
+ sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
+ if (proxyBinder == nullptr) return;
+ proxyBinder->pingForUserUpdate();
+}
+
+void CameraServiceProxyWrapper::updateProxyDeviceState(const CameraSessionStats& sessionStats) {
+ sp<ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
+ if (proxyBinder == nullptr) return;
+ proxyBinder->notifyCameraState(sessionStats);
+}
+
+void CameraServiceProxyWrapper::logStreamConfigured(const String8& id,
+ int operatingMode, bool internalConfig, int32_t latencyMs) {
+ std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
+ {
+ Mutex::Autolock l(mLock);
+ sessionStats = mSessionStatsMap[id];
+ if (sessionStats == nullptr) {
+ ALOGE("%s: SessionStatsMap should contain camera %s",
+ __FUNCTION__, id.c_str());
+ return;
+ }
+ }
+
+ ALOGV("%s: id %s, operatingMode %d, internalConfig %d, latencyMs %d",
+ __FUNCTION__, id.c_str(), operatingMode, internalConfig, latencyMs);
+ sessionStats->onStreamConfigured(operatingMode, internalConfig, latencyMs);
+}
+
+void CameraServiceProxyWrapper::logActive(const String8& id) {
+ std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
+ {
+ Mutex::Autolock l(mLock);
+ sessionStats = mSessionStatsMap[id];
+ if (sessionStats == nullptr) {
+ ALOGE("%s: SessionStatsMap should contain camera %s when logActive is called",
+ __FUNCTION__, id.c_str());
+ return;
+ }
+ }
+
+ ALOGV("%s: id %s", __FUNCTION__, id.c_str());
+ sessionStats->onActive();
+}
+
+void CameraServiceProxyWrapper::logIdle(const String8& id,
+ int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+ const std::vector<hardware::CameraStreamStats>& streamStats) {
+ std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
+ {
+ Mutex::Autolock l(mLock);
+ sessionStats = mSessionStatsMap[id];
+ }
+
+ if (sessionStats == nullptr) {
+ ALOGE("%s: SessionStatsMap should contain camera %s when logIdle is called",
+ __FUNCTION__, id.c_str());
+ return;
+ }
+
+ ALOGV("%s: id %s, requestCount %" PRId64 ", resultErrorCount %" PRId64 ", deviceError %d",
+ __FUNCTION__, id.c_str(), requestCount, resultErrorCount, deviceError);
+ for (size_t i = 0; i < streamStats.size(); i++) {
+ ALOGV("%s: streamStats[%zu]: w %d h %d, requestedCount %" PRId64 ", dropCount %"
+ PRId64 ", startTimeMs %d" ,
+ __FUNCTION__, i, streamStats[i].mWidth, streamStats[i].mHeight,
+ streamStats[i].mRequestCount, streamStats[i].mErrorCount,
+ streamStats[i].mStartLatencyMs);
+ }
+
+ sessionStats->onIdle(requestCount, resultErrorCount, deviceError, streamStats);
+}
+
+void CameraServiceProxyWrapper::logOpen(const String8& id, int facing,
+ const String16& clientPackageName, int effectiveApiLevel, bool isNdk,
+ int32_t latencyMs) {
+ std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
+ {
+ Mutex::Autolock l(mLock);
+ if (mSessionStatsMap.count(id) > 0) {
+ ALOGE("%s: SessionStatsMap shouldn't contain camera %s",
+ __FUNCTION__, id.c_str());
+ return;
+ }
+
+ int apiLevel = CameraSessionStats::CAMERA_API_LEVEL_1;
+ if (effectiveApiLevel == 2) {
+ apiLevel = CameraSessionStats::CAMERA_API_LEVEL_2;
+ }
+
+ sessionStats = std::make_shared<CameraSessionStatsWrapper>(String16(id), facing,
+ CameraSessionStats::CAMERA_STATE_OPEN, clientPackageName,
+ apiLevel, isNdk, latencyMs);
+ mSessionStatsMap.emplace(id, sessionStats);
+ ALOGV("%s: Adding id %s", __FUNCTION__, id.c_str());
+ }
+
+ ALOGV("%s: id %s, facing %d, effectiveApiLevel %d, isNdk %d, latencyMs %d",
+ __FUNCTION__, id.c_str(), facing, effectiveApiLevel, isNdk, latencyMs);
+ sessionStats->onOpen();
+}
+
+void CameraServiceProxyWrapper::logClose(const String8& id, int32_t latencyMs) {
+ std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
+ {
+ Mutex::Autolock l(mLock);
+ if (mSessionStatsMap.count(id) == 0) {
+ ALOGE("%s: SessionStatsMap should contain camera %s before it's closed",
+ __FUNCTION__, id.c_str());
+ return;
+ }
+
+ sessionStats = mSessionStatsMap[id];
+ if (sessionStats == nullptr) {
+ ALOGE("%s: SessionStatsMap should contain camera %s",
+ __FUNCTION__, id.c_str());
+ return;
+ }
+ mSessionStatsMap.erase(id);
+ ALOGV("%s: Erasing id %s", __FUNCTION__, id.c_str());
+ }
+
+ ALOGV("%s: id %s, latencyMs %d", __FUNCTION__, id.c_str(), latencyMs);
+ sessionStats->onClose(latencyMs);
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
new file mode 100644
index 0000000..9525935
--- /dev/null
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 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_SERVERS_CAMERA_SERVICE_PROXY_WRAPPER_H_
+#define ANDROID_SERVERS_CAMERA_SERVICE_PROXY_WRAPPER_H_
+
+#include <android/hardware/ICameraServiceProxy.h>
+
+#include <utils/Mutex.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
+
+#include <camera/CameraSessionStats.h>
+
+namespace android {
+
+class CameraServiceProxyWrapper {
+private:
+ // Guard mCameraServiceProxy
+ static Mutex sProxyMutex;
+ // Cached interface to the camera service proxy in system service
+ static sp<hardware::ICameraServiceProxy> sCameraServiceProxy;
+
+ struct CameraSessionStatsWrapper {
+ hardware::CameraSessionStats mSessionStats;
+ Mutex mLock; // lock for per camera session stats
+
+ CameraSessionStatsWrapper(const String16& cameraId, int facing, int newCameraState,
+ const String16& clientName, int apiLevel, bool isNdk, int32_t latencyMs) :
+ mSessionStats(cameraId, facing, newCameraState, clientName, apiLevel, isNdk, latencyMs)
+ {}
+
+ void onOpen();
+ void onClose(int32_t latencyMs);
+ void onStreamConfigured(int operatingMode, bool internalReconfig, int32_t latencyMs);
+ void onActive();
+ void onIdle(int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+ const std::vector<hardware::CameraStreamStats>& streamStats);
+ };
+
+ // Lock for camera session stats map
+ static Mutex mLock;
+ // Map from camera id to the camera's session statistics
+ static std::map<String8, std::shared_ptr<CameraSessionStatsWrapper>> mSessionStatsMap;
+
+ /**
+ * Update the session stats of a given camera device (open/close/active/idle) with
+ * the camera proxy service in the system service
+ */
+ static void updateProxyDeviceState(
+ const hardware::CameraSessionStats& sessionStats);
+
+ static sp<hardware::ICameraServiceProxy> getCameraServiceProxy();
+
+public:
+ // Open
+ static void logOpen(const String8& id, int facing,
+ const String16& clientPackageName, int apiLevel, bool isNdk,
+ int32_t latencyMs);
+
+ // Close
+ static void logClose(const String8& id, int32_t latencyMs);
+
+ // Stream configuration
+ static void logStreamConfigured(const String8& id, int operatingMode, bool internalReconfig,
+ int32_t latencyMs);
+
+ // Session state becomes active
+ static void logActive(const String8& id);
+
+ // Session state becomes idle
+ static void logIdle(const String8& id,
+ int64_t requestCount, int64_t resultErrorCount, bool deviceError,
+ const std::vector<hardware::CameraStreamStats>& streamStats);
+
+ // Ping camera service proxy for user update
+ static void pingCameraServiceProxy();
+};
+
+} // android
+
+#endif // ANDROID_SERVERS_CAMERA_SERVICE_PROXY_WRAPPER_H_
diff --git a/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp b/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
new file mode 100644
index 0000000..83965c4
--- /dev/null
+++ b/services/camera/libcameraservice/utils/SessionStatsBuilder.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 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 "CameraSessionStatsBuilder"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include "SessionStatsBuilder.h"
+
+namespace android {
+
+status_t SessionStatsBuilder::addStream(int id) {
+ std::lock_guard<std::mutex> l(mLock);
+ StreamStats stats;
+ mStatsMap.emplace(id, stats);
+ return OK;
+}
+
+status_t SessionStatsBuilder::removeStream(int id) {
+ std::lock_guard<std::mutex> l(mLock);
+ mStatsMap.erase(id);
+ return OK;
+}
+
+void SessionStatsBuilder::buildAndReset(int64_t* requestCount,
+ int64_t* errorResultCount, bool* deviceError,
+ std::map<int, StreamStats> *statsMap) {
+ std::lock_guard<std::mutex> l(mLock);
+ *requestCount = mRequestCount;
+ *errorResultCount = mErrorResultCount;
+ *deviceError = mDeviceError;
+ *statsMap = mStatsMap;
+
+ // Reset internal states
+ mRequestCount = 0;
+ mErrorResultCount = 0;
+ mCounterStopped = false;
+ mDeviceError = false;
+ for (auto& streamStats : mStatsMap) {
+ streamStats.second.mRequestedFrameCount = 0;
+ streamStats.second.mDroppedFrameCount = 0;
+ streamStats.second.mCounterStopped = false;
+ streamStats.second.mStartLatencyMs = 0;
+ }
+}
+
+void SessionStatsBuilder::startCounter(int id) {
+ std::lock_guard<std::mutex> l(mLock);
+ mStatsMap[id].mCounterStopped = false;
+}
+
+void SessionStatsBuilder::stopCounter(int id) {
+ std::lock_guard<std::mutex> l(mLock);
+ mStatsMap[id].mCounterStopped = true;
+}
+
+void SessionStatsBuilder::incCounter(int id, bool dropped, int32_t captureLatencyMs) {
+ std::lock_guard<std::mutex> l(mLock);
+ auto it = mStatsMap.find(id);
+ if (it != mStatsMap.end()) {
+ if (!it->second.mCounterStopped) {
+ it->second.mRequestedFrameCount++;
+ if (dropped) {
+ it->second.mDroppedFrameCount++;
+ } else if (it->second.mRequestedFrameCount == 1) {
+ // The capture latency for the first request.
+ it->second.mStartLatencyMs = captureLatencyMs;
+ }
+ }
+ }
+}
+
+void SessionStatsBuilder::stopCounter() {
+ std::lock_guard<std::mutex> l(mLock);
+ mCounterStopped = true;
+ for (auto& streamStats : mStatsMap) {
+ streamStats.second.mCounterStopped = true;
+ }
+}
+
+void SessionStatsBuilder::incResultCounter(bool dropped) {
+ std::lock_guard<std::mutex> l(mLock);
+ if (!mCounterStopped) {
+ mRequestCount ++;
+ if (dropped) mErrorResultCount++;
+ }
+}
+
+void SessionStatsBuilder::onDeviceError() {
+ std::lock_guard<std::mutex> l(mLock);
+ mDeviceError = true;
+}
+
+}; // namespace android
diff --git a/services/camera/libcameraservice/utils/SessionStatsBuilder.h b/services/camera/libcameraservice/utils/SessionStatsBuilder.h
new file mode 100644
index 0000000..7943637
--- /dev/null
+++ b/services/camera/libcameraservice/utils/SessionStatsBuilder.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 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_SERVICE_UTILS_SESSION_STATS_BUILDER_H
+#define ANDROID_SERVICE_UTILS_SESSION_STATS_BUILDER_H
+
+#include <utils/Errors.h>
+
+#include <mutex>
+#include <map>
+
+namespace android {
+
+// Helper class to build stream stats
+struct StreamStats {
+ int64_t mRequestedFrameCount;
+ int64_t mDroppedFrameCount;
+ bool mCounterStopped;
+ int32_t mStartLatencyMs;
+
+ StreamStats() : mRequestedFrameCount(0),
+ mDroppedFrameCount(0),
+ mCounterStopped(false),
+ mStartLatencyMs(0) {}
+};
+
+// Helper class to build session stats
+class SessionStatsBuilder {
+public:
+
+ status_t addStream(int streamId);
+ status_t removeStream(int streamId);
+
+ // Return the session statistics and reset the internal states.
+ void buildAndReset(/*out*/int64_t* requestCount,
+ /*out*/int64_t* errorResultCount,
+ /*out*/bool* deviceError,
+ /*out*/std::map<int, StreamStats> *statsMap);
+
+ // Stream specific counter
+ void startCounter(int streamId);
+ void stopCounter(int streamId);
+ void incCounter(int streamId, bool dropped, int32_t captureLatencyMs);
+
+ // Session specific counter
+ void stopCounter();
+ void incResultCounter(bool dropped);
+ void onDeviceError();
+
+ SessionStatsBuilder() : mRequestCount(0), mErrorResultCount(0),
+ mCounterStopped(false), mDeviceError(false) {}
+private:
+ std::mutex mLock;
+ int64_t mRequestCount;
+ int64_t mErrorResultCount;
+ bool mCounterStopped;
+ bool mDeviceError;
+ // Map from stream id to stream statistics
+ std::map<int, StreamStats> mStatsMap;
+};
+
+}; // namespace android
+
+#endif // ANDROID_SERVICE_UTILS_SESSION_STATS_BUILDER_H