Track camera and flashlight usage in battery stats.

Bug: 15986092

Change-Id: I9dc6828332e4091fd93bf2d82839e8e3862a2fc2
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