mediaresourcemanager: add ServiceLog to track the calling history for dumpsys.

Bug: 20637674
Change-Id: I9d74d98f8eb729a8681877f86419aa2c979f3b7c
diff --git a/services/mediaresourcemanager/Android.mk b/services/mediaresourcemanager/Android.mk
index 84218cf..b72230f 100644
--- a/services/mediaresourcemanager/Android.mk
+++ b/services/mediaresourcemanager/Android.mk
@@ -2,7 +2,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES := ResourceManagerService.cpp
+LOCAL_SRC_FILES := ResourceManagerService.cpp ServiceLog.cpp
 
 LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils liblog
 
@@ -13,6 +13,9 @@
 LOCAL_C_INCLUDES += \
     $(TOPDIR)frameworks/av/include
 
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 17aac4e..e3f70ff 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -29,6 +29,7 @@
 #include <unistd.h>
 
 #include "ResourceManagerService.h"
+#include "ServiceLog.h"
 
 namespace android {
 
@@ -88,7 +89,7 @@
     return infos.editItemAt(infos.size() - 1);
 }
 
-status_t ResourceManagerService::dump(int fd, const Vector<String16>& args) {
+status_t ResourceManagerService::dump(int fd, const Vector<String16>& /* args */) {
     Mutex::Autolock lock(mLock);
 
     String8 result;
@@ -103,16 +104,14 @@
     snprintf(buffer, SIZE, "    SupportsSecureWithNonSecureCodec: %d\n", mSupportsSecureWithNonSecureCodec);
     result.append(buffer);
 
-    snprintf(buffer, SIZE, "  Processes:\n");
-    result.append(buffer);
+    result.append("  Processes:\n");
     for (size_t i = 0; i < mMap.size(); ++i) {
         snprintf(buffer, SIZE, "    Pid: %d\n", mMap.keyAt(i));
         result.append(buffer);
 
         const ResourceInfos &infos = mMap.valueAt(i);
         for (size_t j = 0; j < infos.size(); ++j) {
-            snprintf(buffer, SIZE, "      Client:\n");
-            result.append(buffer);
+            result.append("      Client:\n");
             snprintf(buffer, SIZE, "        Id: %lld\n", (long long)infos[j].clientId);
             result.append(buffer);
 
@@ -120,14 +119,15 @@
             result.append(buffer);
 
             Vector<MediaResource> resources = infos[j].resources;
-            snprintf(buffer, SIZE, "        Resources:\n");
-            result.append(buffer);
+            result.append("        Resources:\n");
             for (size_t k = 0; k < resources.size(); ++k) {
                 snprintf(buffer, SIZE, "          %s\n", resources[k].toString().string());
                 result.append(buffer);
             }
         }
     }
+    result.append("  Logs:\n");
+    result.append(mServiceLog->toString());
 
     write(fd, result.string(), result.size());
     return OK;
@@ -135,18 +135,21 @@
 
 ResourceManagerService::ResourceManagerService()
     : mProcessInfo(new ProcessInfo()),
+      mServiceLog(new ServiceLog()),
       mSupportsMultipleSecureCodecs(true),
       mSupportsSecureWithNonSecureCodec(true) {}
 
 ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
     : mProcessInfo(processInfo),
+      mServiceLog(new ServiceLog()),
       mSupportsMultipleSecureCodecs(true),
       mSupportsSecureWithNonSecureCodec(true) {}
 
 ResourceManagerService::~ResourceManagerService() {}
 
 void ResourceManagerService::config(const Vector<MediaResourcePolicy> &policies) {
-    ALOGV("config(%s)", getString(policies).string());
+    String8 log = String8::format("config(%s)", getString(policies).string());
+    mServiceLog->add(log);
 
     Mutex::Autolock lock(mLock);
     for (size_t i = 0; i < policies.size(); ++i) {
@@ -165,8 +168,9 @@
         int64_t clientId,
         const sp<IResourceManagerClient> client,
         const Vector<MediaResource> &resources) {
-    ALOGV("addResource(pid %d, clientId %lld, resources %s)",
+    String8 log = String8::format("addResource(pid %d, clientId %lld, resources %s)",
             pid, (long long) clientId, getString(resources).string());
+    mServiceLog->add(log);
 
     Mutex::Autolock lock(mLock);
     ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
@@ -176,7 +180,8 @@
 }
 
 void ResourceManagerService::removeResource(int64_t clientId) {
-    ALOGV("removeResource(%lld)", (long long) clientId);
+    String8 log = String8::format("removeResource(%lld)", (long long) clientId);
+    mServiceLog->add(log);
 
     Mutex::Autolock lock(mLock);
     bool found = false;
@@ -201,8 +206,9 @@
 
 bool ResourceManagerService::reclaimResource(
         int callingPid, const Vector<MediaResource> &resources) {
-    ALOGV("reclaimResource(callingPid %d, resources %s)",
+    String8 log = String8::format("reclaimResource(callingPid %d, resources %s)",
             callingPid, getString(resources).string());
+    mServiceLog->add(log);
 
     Vector<sp<IResourceManagerClient>> clients;
     {
@@ -265,7 +271,8 @@
 
     sp<IResourceManagerClient> failedClient;
     for (size_t i = 0; i < clients.size(); ++i) {
-        ALOGV("reclaimResource from client %p", clients[i].get());
+        log = String8::format("reclaimResource from client %p", clients[i].get());
+        mServiceLog->add(log);
         if (!clients[i]->reclaimResource()) {
             failedClient = clients[i];
             break;
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 0c3d694..0d9d878 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -30,6 +30,7 @@
 
 namespace android {
 
+class ServiceLog;
 struct ProcessInfoInterface;
 
 struct ResourceInfo {
@@ -96,6 +97,7 @@
 
     mutable Mutex mLock;
     sp<ProcessInfoInterface> mProcessInfo;
+    sp<ServiceLog> mServiceLog;
     PidResourceInfosMap mMap;
     bool mSupportsMultipleSecureCodecs;
     bool mSupportsSecureWithNonSecureCodec;
diff --git a/services/mediaresourcemanager/ServiceLog.cpp b/services/mediaresourcemanager/ServiceLog.cpp
new file mode 100644
index 0000000..be7b308
--- /dev/null
+++ b/services/mediaresourcemanager/ServiceLog.cpp
@@ -0,0 +1,54 @@
+/*
+**
+** 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ServiceLog"
+#include <utils/Log.h>
+
+#include <time.h>
+
+#include "ServiceLog.h"
+
+static const size_t kDefaultMaxNum = 100;
+
+namespace android {
+
+ServiceLog::ServiceLog() : mMaxNum(kDefaultMaxNum) {}
+ServiceLog::ServiceLog(size_t maxNum) : mMaxNum(maxNum) {}
+
+void ServiceLog::add(const String8 &log) {
+    Mutex::Autolock lock(mLock);
+    time_t now = time(0);
+    char buf[64];
+    strftime(buf, sizeof(buf), "%m-%d %T", localtime(&now));
+    String8 formattedLog = String8::format("%s %s", buf, log.string());
+    if (mLogs.add(formattedLog) == mMaxNum) {
+        mLogs.removeAt(0);
+    }
+}
+
+String8 ServiceLog::toString() const {
+    Mutex::Autolock lock(mLock);
+    String8 result;
+    for (size_t i = 0; i < mLogs.size(); ++i) {
+        result.append(mLogs[i]);
+        result.append("\n");
+    }
+    return result;
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ServiceLog.h b/services/mediaresourcemanager/ServiceLog.h
new file mode 100644
index 0000000..14814ff
--- /dev/null
+++ b/services/mediaresourcemanager/ServiceLog.h
@@ -0,0 +1,46 @@
+/*
+**
+** 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 ANDROID_SERVICELOG_H
+#define ANDROID_SERVICELOG_H
+
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class ServiceLog : public RefBase {
+public:
+    ServiceLog();
+    ServiceLog(size_t maxNum);
+
+    void add(const String8 &log);
+    String8 toString() const;
+
+private:
+    int mMaxNum;
+    mutable Mutex mLock;
+    Vector<String8> mLogs;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_SERVICELOG_H
diff --git a/services/mediaresourcemanager/test/Android.mk b/services/mediaresourcemanager/test/Android.mk
index 228b62a..3b4ef0d 100644
--- a/services/mediaresourcemanager/test/Android.mk
+++ b/services/mediaresourcemanager/test/Android.mk
@@ -20,6 +20,35 @@
   frameworks/av/include \
   frameworks/av/services/mediaresourcemanager \
 
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
+LOCAL_32_BIT_ONLY := true
+
+include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := ServiceLog_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+  ServiceLog_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+  liblog \
+  libmedia \
+  libresourcemanagerservice \
+  libutils \
+
+LOCAL_C_INCLUDES := \
+  frameworks/av/include \
+  frameworks/av/services/mediaresourcemanager \
+
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CLANG := true
+
 LOCAL_32_BIT_ONLY := true
 
 include $(BUILD_NATIVE_TEST)
diff --git a/services/mediaresourcemanager/test/ServiceLog_test.cpp b/services/mediaresourcemanager/test/ServiceLog_test.cpp
new file mode 100644
index 0000000..6ddcb87
--- /dev/null
+++ b/services/mediaresourcemanager/test/ServiceLog_test.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ServiceLog_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include "ServiceLog.h"
+
+namespace android {
+
+class ServiceLogTest : public ::testing::Test {
+public:
+    ServiceLogTest() : mServiceLog(new ServiceLog(3)) {
+    }
+
+protected:
+    sp<ServiceLog> mServiceLog;
+};
+
+TEST_F(ServiceLogTest, addThenToString) {
+    mServiceLog->add(String8("log1"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log1"));
+    ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+    mServiceLog->add(String8("log2"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log1"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log2"));
+    ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+    mServiceLog->add(String8("log3"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log1"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log2"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log3"));
+    ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+    mServiceLog->add(String8("log4"));
+    EXPECT_FALSE(mServiceLog->toString().contains("log1"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log2"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log3"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log4"));
+    ALOGV("toString:\n%s", mServiceLog->toString().string());
+
+    mServiceLog->add(String8("log5"));
+    EXPECT_FALSE(mServiceLog->toString().contains("log1"));
+    EXPECT_FALSE(mServiceLog->toString().contains("log2"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log3"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log4"));
+    EXPECT_TRUE(mServiceLog->toString().contains("log5"));
+    ALOGV("toString:\n%s", mServiceLog->toString().string());
+}
+
+} // namespace android