MediaMetrics: Update to use STL containers

Test: dumpsys media.metrics sanity
Change-Id: Ifcada098e755ef3d679715ed23fab9d793ebde3e
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index b7856a6..c8713bf 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -234,10 +234,6 @@
     return *this;
 }
 
-MediaAnalyticsItem::Key MediaAnalyticsItem::getKey() {
-    return mKey;
-}
-
 // number of attributes we have in this record
 int32_t MediaAnalyticsItem::count() const {
     return mPropCount;
@@ -795,11 +791,11 @@
     return strdup(val.c_str());
 }
 
-std::string MediaAnalyticsItem::toString() {
+std::string MediaAnalyticsItem::toString() const {
    return toString(PROTO_LAST);
 }
 
-std::string MediaAnalyticsItem::toString(int version) {
+std::string MediaAnalyticsItem::toString(int version) const {
 
     // v0 : released with 'o'
     // v1 : bug fix (missing pid/finalized separator),
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index 42a2f5b..3024c84 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -119,7 +119,7 @@
         // set the key discriminator for the record.
         // most often initialized as part of the constructor
         MediaAnalyticsItem &setKey(MediaAnalyticsItem::Key);
-        MediaAnalyticsItem::Key getKey();
+        const MediaAnalyticsItem::Key& getKey() const { return mKey; }
 
         // # of attributes in the record
         int32_t count() const;
@@ -191,8 +191,8 @@
         // supports the stable interface
         bool dumpAttributes(char **pbuffer, size_t *plength);
 
-        std::string toString();
-        std::string toString(int version);
+        std::string toString() const;
+        std::string toString(int version) const;
         const char *toCString();
         const char *toCString(int version);
 
diff --git a/services/mediaanalytics/Android.bp b/services/mediaanalytics/Android.bp
index c27aced..80816d7 100644
--- a/services/mediaanalytics/Android.bp
+++ b/services/mediaanalytics/Android.bp
@@ -5,9 +5,9 @@
     name: "mediametrics",
 
     srcs: [
+        "iface_statsd.cpp",
         "main_mediametrics.cpp",
         "MediaAnalyticsService.cpp",
-        "iface_statsd.cpp",
         "statsd_audiopolicy.cpp",
         "statsd_audiorecord.cpp",
         "statsd_audiothread.cpp",
@@ -24,44 +24,28 @@
     },
 
     shared_libs: [
-        "libcutils",
-        "liblog",
-        "libmedia",
-        "libutils",
         "libbinder",
-        "libdl",
-        "libgui",
-        "libmedia",
-        "libmediautils",
+        "liblog",
         "libmediametrics",
-        "libstagefright_foundation",
+        "libprotobuf-cpp-lite",
         "libstatslog",
         "libutils",
-        "libprotobuf-cpp-lite",
     ],
 
     static_libs: [
         "libplatformprotos",
-        "libregistermsext",
     ],
 
     include_dirs: [
-        "frameworks/av/media/libstagefright/include",
-        "frameworks/av/media/libstagefright/rtsp",
-        "frameworks/av/media/libstagefright/webm",
-        "frameworks/av/include/media",
-        "frameworks/av/camera/include/camera",
-        "frameworks/native/include/media/openmax",
-        "frameworks/native/include/media/hardware",
-        "external/tremolo/Tremolo",
+        "system/media/audio_utils/include"
     ],
 
     init_rc: ["mediametrics.rc"],
 
     cflags: [
-        "-Werror",
         "-Wall",
-        "-Wno-error=deprecated-declarations",
+        "-Werror",
+        "-Wextra",
     ],
     clang: true,
 
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 988c06b..42afc6b 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -14,66 +14,20 @@
  * limitations under the License.
  */
 
-// Proxy for media player implementations
-
 //#define LOG_NDEBUG 0
 #define LOG_TAG "MediaAnalyticsService"
 #include <utils/Log.h>
 
-#include <stdint.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <dirent.h>
-#include <pthread.h>
-#include <unistd.h>
-
-#include <string.h>
-#include <pwd.h>
-
-#include <cutils/atomic.h>
-#include <cutils/properties.h> // for property_get
-
-#include <utils/misc.h>
-
-#include <android/content/pm/IPackageManagerNative.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/MemoryHeapBase.h>
-#include <binder/MemoryBase.h>
-#include <gui/Surface.h>
-#include <utils/Errors.h>  // for status_t
-#include <utils/List.h>
-#include <utils/String8.h>
-#include <utils/SystemClock.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-#include <media/IMediaHTTPService.h>
-#include <media/IRemoteDisplay.h>
-#include <media/IRemoteDisplayClient.h>
-#include <media/MediaPlayerInterface.h>
-#include <media/mediarecorder.h>
-#include <media/MediaMetadataRetrieverInterface.h>
-#include <media/Metadata.h>
-#include <media/AudioTrack.h>
-#include <media/MemoryLeakTrackUtil.h>
-#include <media/stagefright/MediaCodecList.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooperRoster.h>
-#include <mediautils/BatteryNotifier.h>
-
-//#include <memunreachable/memunreachable.h>
-#include <system/audio.h>
-
-#include <private/android_filesystem_config.h>
-
 #include "MediaAnalyticsService.h"
 
+#include <pwd.h> //getpwuid
+
+#include <audio_utils/clock.h>                 // clock conversions
+#include <android/content/pm/IPackageManagerNative.h>  // package info
+#include <binder/IPCThreadState.h>             // get calling uid
+#include <cutils/properties.h>                 // for property_get
+#include <private/android_filesystem_config.h> // UID
+
 namespace android {
 
 // individual records kept in memory: age or count
@@ -81,72 +35,45 @@
 // count: hard limit of # records
 // (0 for either of these disables that threshold)
 //
-static constexpr nsecs_t kMaxRecordAgeNs =  28 * 3600 * (1000*1000*1000ll);
+static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * NANOS_PER_SECOND;
 // 2019/6: average daily per device is currently 375-ish;
 // setting this to 2000 is large enough to catch most devices
 // we'll lose some data on very very media-active devices, but only for
 // the gms collection; statsd will have already covered those for us.
 // This also retains enough information to help with bugreports
-static constexpr int kMaxRecords    = 2000;
+static constexpr size_t kMaxRecords = 2000;
 
 // max we expire in a single call, to constrain how long we hold the
 // mutex, which also constrains how long a client might wait.
-static constexpr int kMaxExpiredAtOnce = 50;
+static constexpr size_t kMaxExpiredAtOnce = 50;
 
 // TODO: need to look at tuning kMaxRecords and friends for low-memory devices
 
-static const char *kServiceName = "media.metrics";
-
-void MediaAnalyticsService::instantiate() {
-    defaultServiceManager()->addService(
-            String16(kServiceName), new MediaAnalyticsService());
-}
-
 MediaAnalyticsService::MediaAnalyticsService()
         : mMaxRecords(kMaxRecords),
           mMaxRecordAgeNs(kMaxRecordAgeNs),
           mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce),
-          mDumpProto(MediaAnalyticsItem::PROTO_V1),
-          mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
-
-    ALOGD("MediaAnalyticsService created");
-
-    mItemsSubmitted = 0;
-    mItemsFinalized = 0;
-    mItemsDiscarded = 0;
-    mItemsDiscardedExpire = 0;
-    mItemsDiscardedCount = 0;
-
-    mLastSessionID = 0;
-    // recover any persistency we set up
-    // etc
+          mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1)
+{
+    ALOGD("%s", __func__);
 }
 
-MediaAnalyticsService::~MediaAnalyticsService() {
-        ALOGD("MediaAnalyticsService destroyed");
-
-    while (mItems.size() > 0) {
-        MediaAnalyticsItem * oitem = *(mItems.begin());
-        mItems.erase(mItems.begin());
-        delete oitem;
-        mItemsDiscarded++;
-        mItemsDiscardedCount++;
-    }
+MediaAnalyticsService::~MediaAnalyticsService()
+{
+    ALOGD("%s", __func__);
+    // the class destructor clears anyhow, but we enforce clearing items first.
+    mItemsDiscarded += mItems.size();
+    mItems.clear();
 }
 
-
 MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
-    // generate a new sessionid
-
-    Mutex::Autolock _l(mLock_ids);
-    return (++mLastSessionID);
+    return ++mLastSessionID;
 }
 
-// caller surrenders ownership of 'item'
-MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew)
+// TODO: consider removing forcenew.
+MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(
+        MediaAnalyticsItem *item, bool forcenew __unused)
 {
-    UNUSED(forcenew);
-
     // fill in a sessionID if we do not yet have one
     if (item->getSessionID() <= MediaAnalyticsItem::SessionIDNone) {
         item->setSessionID(generateUniqueSessionID());
@@ -155,61 +82,60 @@
     // we control these, generally not trusting user input
     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
     // round nsecs to seconds
-    now = ((now + 500000000) / 1000000000) * 1000000000;
+    now = (now + NANOS_PER_SECOND / 2) / NANOS_PER_SECOND * NANOS_PER_SECOND;
+    // TODO: if we convert to boot time, do we need to round timestamp?
     item->setTimestamp(now);
-    int pid = IPCThreadState::self()->getCallingPid();
-    int uid = IPCThreadState::self()->getCallingUid();
 
-    int uid_given = item->getUid();
-    int pid_given = item->getPid();
+    const int pid = IPCThreadState::self()->getCallingPid();
+    const int uid = IPCThreadState::self()->getCallingUid();
+    const int uid_given = item->getUid();
+    const int pid_given = item->getPid();
 
-    // although we do make exceptions for some trusted client uids
-    bool isTrusted = false;
-
-    ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
-
-    switch (uid)  {
-        case AID_DRM:
-        case AID_MEDIA:
-        case AID_MEDIA_CODEC:
-        case AID_MEDIA_EX:
-        case AID_MEDIA_DRM:
-            // trusted source, only override default values
-            isTrusted = true;
-            if (uid_given == (-1)) {
-                item->setUid(uid);
-            }
-            if (pid_given == (-1)) {
-                item->setPid(pid);
-            }
-            break;
-        default:
-            isTrusted = false;
-            item->setPid(pid);
+    ALOGV("%s: caller has uid=%d, embedded uid=%d", __func__, uid, uid_given);
+    bool isTrusted;
+    switch (uid) {
+    case AID_DRM:
+    case AID_MEDIA:
+    case AID_MEDIA_CODEC:
+    case AID_MEDIA_EX:
+    case AID_MEDIA_DRM:
+        // trusted source, only override default values
+        isTrusted = true;
+        if (uid_given == -1) {
             item->setUid(uid);
-            break;
+        }
+        if (pid_given == -1) {
+            item->setPid(pid);
+        }
+        break;
+    default:
+        isTrusted = false;
+        item->setPid(pid);
+        item->setUid(uid);
+        break;
     }
 
     // Overwrite package name and version if the caller was untrusted.
     if (!isTrusted) {
-      setPkgInfo(item, item->getUid(), true, true);
+        mUidInfo.setPkgInfo(item, item->getUid(), true, true);
     } else if (item->getPkgName().empty()) {
-      // empty, so fill out both parts
-      setPkgInfo(item, item->getUid(), true, true);
+        // empty, so fill out both parts
+        mUidInfo.setPkgInfo(item, item->getUid(), true, true);
     } else {
-      // trusted, provided a package, do nothing
+        // trusted, provided a package, do nothing
     }
 
-    ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
-          "sanitized pkg version: %"  PRId64,
+    ALOGV("%s: given uid %d; sanitized uid: %d sanitized pkg: %s "
+          "sanitized pkg version: %lld",
+          __func__,
           uid_given, item->getUid(),
           item->getPkgName().c_str(),
-          item->getPkgVersionCode());
+          (long long)item->getPkgVersionCode());
 
     mItemsSubmitted++;
 
     // validate the record; we discard if we don't like it
-    if (contentValid(item, isTrusted) == false) {
+    if (isContentValid(item, isTrusted) == false) {
         delete item;
         return MediaAnalyticsItem::SessionIDInvalid;
     }
@@ -218,56 +144,46 @@
     // sure it doesn't appear in the finalized list.
 
     if (item->count() == 0) {
-        ALOGV("dropping empty record...");
+        ALOGV("%s: dropping empty record...", __func__);
         delete item;
-        item = NULL;
         return MediaAnalyticsItem::SessionIDInvalid;
     }
 
-    // save the new record
-    //
-    // send a copy to statsd
-    dump2Statsd(item);
+    // send to statsd
+    extern bool dump2Statsd(MediaAnalyticsItem *item);  // extern hook
+    (void)dump2Statsd(item);  // failure should be logged in function.
 
-    // and keep our copy for dumpsys
-    MediaAnalyticsItem::SessionID_t id = item->getSessionID();
+    // keep our copy
+    const MediaAnalyticsItem::SessionID_t id = item->getSessionID();
     saveItem(item);
-    mItemsFinalized++;
-
     return id;
 }
 
-
 status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
 {
-    const size_t SIZE = 512;
-    char buffer[SIZE];
     String8 result;
 
     if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
-        snprintf(buffer, SIZE, "Permission Denial: "
+        result.appendFormat("Permission Denial: "
                 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
                 IPCThreadState::self()->getCallingPid(),
                 IPCThreadState::self()->getCallingUid());
-        result.append(buffer);
         write(fd, result.string(), result.size());
         return NO_ERROR;
     }
 
     // crack any parameters
-    String16 protoOption("-proto");
+    const String16 protoOption("-proto");
     int chosenProto = mDumpProtoDefault;
-    String16 clearOption("-clear");
+    const String16 clearOption("-clear");
     bool clear = false;
-    String16 sinceOption("-since");
+    const String16 sinceOption("-since");
     nsecs_t ts_since = 0;
-    String16 helpOption("-help");
-    String16 onlyOption("-only");
+    const String16 helpOption("-help");
+    const String16 onlyOption("-only");
     std::string only;
-    int n = args.size();
-
+    const int n = args.size();
     for (int i = 0; i < n; i++) {
-        String8 myarg(args[i]);
         if (args[i] == clearOption) {
             clear = true;
         } else if (args[i] == protoOption) {
@@ -305,7 +221,7 @@
                 ts_since = 0;
             }
             // command line is milliseconds; internal units are nano-seconds
-            ts_since *= 1000*1000;
+            ts_since *= NANOS_PER_MILLISECOND;
         } else if (args[i] == onlyOption) {
             i++;
             if (i < n) {
@@ -313,6 +229,10 @@
                 only = value.string();
             }
         } else if (args[i] == helpOption) {
+            // TODO: consider function area dumping.
+            // dumpsys media.metrics audiotrack,codec
+            // or dumpsys media.metrics audiotrack codec
+
             result.append("Recognized parameters:\n");
             result.append("-help        this help message\n");
             result.append("-proto #     dump using protocol #");
@@ -325,31 +245,18 @@
         }
     }
 
-    Mutex::Autolock _l(mLock);
-    // mutex between insertion and dumping the contents
+    {
+        std::lock_guard _l(mLock);
 
-    mDumpProto = chosenProto;
+        result.appendFormat("Dump of the %s process:\n", kServiceName);
+        dumpHeaders_l(result, chosenProto, ts_since);
+        dumpRecent_l(result, chosenProto, ts_since, only.c_str());
 
-    // we ALWAYS dump this piece
-    snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
-    result.append(buffer);
-
-    dumpHeaders(result, ts_since);
-
-    dumpRecent(result, ts_since, only.c_str());
-
-
-    if (clear) {
-        // remove everything from the finalized queue
-        while (mItems.size() > 0) {
-            MediaAnalyticsItem * oitem = *(mItems.begin());
-            mItems.erase(mItems.begin());
-            delete oitem;
-            mItemsDiscarded++;
+        if (clear) {
+            mItemsDiscarded += mItems.size();
+            mItems.clear();
+            // shall we clear the summary data too?
         }
-
-        // shall we clear the summary data too?
-
     }
 
     write(fd, result.string(), result.size());
@@ -357,275 +264,207 @@
 }
 
 // dump headers
-void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since)
+void MediaAnalyticsService::dumpHeaders_l(String8 &result, int dumpProto, nsecs_t ts_since)
 {
-    const size_t SIZE = 512;
-    char buffer[SIZE];
-
-    snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
-    result.append(buffer);
-
-    int enabled = MediaAnalyticsItem::isEnabled();
-    if (enabled) {
-        snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
+    result.appendFormat("Protocol Version: %d\n", dumpProto);
+    if (MediaAnalyticsItem::isEnabled()) {
+        result.append("Metrics gathering: enabled\n");
     } else {
-        snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
+        result.append("Metrics gathering: DISABLED via property\n");
     }
-    result.append(buffer);
-
-    snprintf(buffer, SIZE,
-        "Since Boot: Submissions: %8" PRId64
-            " Accepted: %8" PRId64 "\n",
-        mItemsSubmitted, mItemsFinalized);
-    result.append(buffer);
-    snprintf(buffer, SIZE,
-        "Records Discarded: %8" PRId64
-            " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
-         mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
-    result.append(buffer);
+    result.appendFormat(
+            "Since Boot: Submissions: %lld Accepted: %lld\n",
+            (long long)mItemsSubmitted.load(), (long long)mItemsFinalized);
+    result.appendFormat(
+            "Records Discarded: %lld (by Count: %lld by Expiration: %lld)\n",
+            (long long)mItemsDiscarded, (long long)mItemsDiscardedCount,
+            (long long)mItemsDiscardedExpire);
     if (ts_since != 0) {
-        snprintf(buffer, SIZE,
-            "Emitting Queue entries more recent than: %" PRId64 "\n",
-            (int64_t) ts_since);
-        result.append(buffer);
+        result.appendFormat(
+            "Emitting Queue entries more recent than: %lld\n",
+            (long long)ts_since);
     }
 }
 
-// the recent, detailed queues
-void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only)
+void MediaAnalyticsService::dumpRecent_l(
+        String8 &result, int dumpProto, nsecs_t ts_since, const char * only)
 {
-    const size_t SIZE = 512;
-    char buffer[SIZE];
-
-    if (only != NULL && *only == '\0') {
-        only = NULL;
+    if (only != nullptr && *only == '\0') {
+        only = nullptr;
     }
-
-    // show the recently recorded records
-    snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
-    result.append(buffer);
-    result.append(this->dumpQueue(ts_since, only));
+    result.append("\nFinalized Metrics (oldest first):\n");
+    dumpQueue_l(result, dumpProto, ts_since, only);
 
     // show who is connected and injecting records?
     // talk about # records fed to the 'readers'
     // talk about # records we discarded, perhaps "discarded w/o reading" too
 }
 
-// caller has locked mLock...
-String8 MediaAnalyticsService::dumpQueue() {
-    return dumpQueue((nsecs_t) 0, NULL);
+void MediaAnalyticsService::dumpQueue_l(String8 &result, int dumpProto) {
+    dumpQueue_l(result, dumpProto, (nsecs_t) 0, nullptr /* only */);
 }
 
-String8 MediaAnalyticsService::dumpQueue(nsecs_t ts_since, const char * only) {
-    String8 result;
+void MediaAnalyticsService::dumpQueue_l(
+        String8 &result, int dumpProto, nsecs_t ts_since, const char * only) {
     int slot = 0;
 
     if (mItems.empty()) {
-            result.append("empty\n");
+        result.append("empty\n");
     } else {
-        List<MediaAnalyticsItem *>::iterator it = mItems.begin();
-        for (; it != mItems.end(); it++) {
-            nsecs_t when = (*it)->getTimestamp();
+        for (const auto &item : mItems) {
+            nsecs_t when = item->getTimestamp();
             if (when < ts_since) {
                 continue;
             }
-            if (only != NULL &&
-                strcmp(only, (*it)->getKey().c_str()) != 0) {
-                ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
+            // TODO: Only should be a set<string>
+            if (only != nullptr &&
+                    item->getKey() /* std::string */ != only) {
+                ALOGV("%s: omit '%s', it's not '%s'",
+                        __func__, item->getKey().c_str(), only);
                 continue;
             }
-            std::string entry = (*it)->toString(mDumpProto);
-            result.appendFormat("%5d: %s\n", slot, entry.c_str());
+            result.appendFormat("%5d: %s\n",
+                   slot, item->toString(dumpProto).c_str());
             slot++;
         }
     }
-
-    return result;
 }
 
 //
 // Our Cheap in-core, non-persistent records management.
 
-
-// we hold mLock when we get here
 // if item != NULL, it's the item we just inserted
 // true == more items eligible to be recovered
 bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
 {
     bool more = false;
-    int handled = 0;
 
-    // keep removing old records the front until we're in-bounds (count)
-    // since we invoke this with each insertion, it should be 0/1 iterations.
-    if (mMaxRecords > 0) {
-        while (mItems.size() > (size_t) mMaxRecords) {
-            MediaAnalyticsItem * oitem = *(mItems.begin());
-            if (oitem == item) {
-                break;
-            }
-            if (handled >= mMaxRecordsExpiredAtOnce) {
-                // unlikely in this loop
-                more = true;
-                break;
-            }
-            handled++;
-            mItems.erase(mItems.begin());
-            delete oitem;
-            mItemsDiscarded++;
-            mItemsDiscardedCount++;
+    // check queue size
+    size_t overlimit = 0;
+    if (mMaxRecords > 0 && mItems.size() > mMaxRecords) {
+        overlimit = mItems.size() - mMaxRecords;
+        if (overlimit > mMaxRecordsExpiredAtOnce) {
+            more = true;
+            overlimit = mMaxRecordsExpiredAtOnce;
         }
     }
 
-    // keep removing old records the front until we're in-bounds (age)
-    // limited to mMaxRecordsExpiredAtOnce items per invocation.
-    if (mMaxRecordAgeNs > 0) {
-        nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
-        while (mItems.size() > 0) {
-            MediaAnalyticsItem * oitem = *(mItems.begin());
+    // check queue times
+    size_t expired = 0;
+    if (!more && mMaxRecordAgeNs > 0) {
+        const nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+        // we check one at a time, skip search would be more efficient.
+        size_t i = overlimit;
+        for (; i < mItems.size(); ++i) {
+            auto &oitem = mItems[i];
             nsecs_t when = oitem->getTimestamp();
-            if (oitem == item) {
+            if (oitem.get() == item) {
                 break;
             }
-            // careful about timejumps too
-            if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
-                // this (and the rest) are recent enough to keep
-                break;
+            if (now > when && (now - when) <= mMaxRecordAgeNs) {
+                break;  // TODO: if we use BOOTTIME, should be monotonic.
             }
-            if (handled >= mMaxRecordsExpiredAtOnce) {
+            if (i >= mMaxRecordsExpiredAtOnce) {
                 // this represents "one too many"; tell caller there are
                 // more to be reclaimed.
                 more = true;
                 break;
             }
-            handled++;
-            mItems.erase(mItems.begin());
-            delete oitem;
-            mItemsDiscarded++;
-            mItemsDiscardedExpire++;
         }
+        expired = i - overlimit;
     }
 
-    // we only indicate whether there's more to clean;
-    // caller chooses whether to schedule further cleanup.
+    if (const size_t toErase = overlimit + expired;
+            toErase > 0) {
+        mItemsDiscardedCount += overlimit;
+        mItemsDiscardedExpire += expired;
+        mItemsDiscarded += toErase;
+        mItems.erase(mItems.begin(), mItems.begin() + toErase); // erase from front
+    }
     return more;
 }
 
-// process expirations in bite sized chunks, allowing new insertions through
-// runs in a pthread specifically started for this (which then exits)
-bool MediaAnalyticsService::processExpirations()
+void MediaAnalyticsService::processExpirations()
 {
     bool more;
     do {
         sleep(1);
-        {
-            Mutex::Autolock _l(mLock);
-            more = expirations_l(NULL);
-            if (!more) {
-                break;
-            }
-        }
+        std::lock_guard _l(mLock);
+        more = expirations_l(nullptr);
     } while (more);
-    return true;        // value is for std::future thread synchronization
 }
 
-// insert appropriately into queue
-void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
+void MediaAnalyticsService::saveItem(MediaAnalyticsItem *item)
 {
-
-    Mutex::Autolock _l(mLock);
-    // mutex between insertion and dumping the contents
-
-    // we want to dump 'in FIFO order', so insert at the end
-    mItems.push_back(item);
-
-    // clean old stuff from the queue
-    bool more = expirations_l(item);
-
-    // consider scheduling some asynchronous cleaning, if not running
-    if (more) {
-        if (!mExpireFuture.valid()
-            || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
-
-            mExpireFuture = std::async(std::launch::async, [this]()
-                                       {return this->processExpirations();});
-        }
+    std::lock_guard _l(mLock);
+    // we assume the items are roughly in time order.
+    mItems.emplace_back(item);
+    ++mItemsFinalized;
+    if (expirations_l(item)
+            && (!mExpireFuture.valid()
+               || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready)) {
+        mExpireFuture = std::async(std::launch::async, [this] { processExpirations(); });
     }
 }
 
-static std::string allowedKeys[] =
+/* static */
+bool MediaAnalyticsService::isContentValid(const MediaAnalyticsItem *item, bool isTrusted)
 {
-    "audiopolicy",
-    "audiorecord",
-    "audiothread",
-    "audiotrack",
-    "codec",
-    "extractor",
-    "nuplayer",
-};
-
-static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
-
-// are the contents good
-bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
-
+    if (isTrusted) return true;
     // untrusted uids can only send us a limited set of keys
-    if (isTrusted == false) {
-        // restrict to a specific set of keys
-        std::string key = item->getKey();
-
-        size_t i;
-        for(i = 0; i < nAllowedKeys; i++) {
-            if (key == allowedKeys[i]) {
-                break;
-            }
-        }
-        if (i == nAllowedKeys) {
-            ALOGD("Ignoring (key): %s", item->toString().c_str());
-            return false;
+    const std::string &key = item->getKey();
+    for (const char *allowedKey : {
+                                     "audiopolicy",
+                                     "audiorecord",
+                                     "audiothread",
+                                     "audiotrack",
+                                     "codec",
+                                     "extractor",
+                                     "nuplayer",
+                                 }) {
+        if (key == allowedKey) {
+            return true;
         }
     }
-
-    // internal consistency
-
-    return true;
-}
-
-// are we rate limited, normally false
-bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
-
+    ALOGD("%s: invalid key: %s", __func__, item->toString().c_str());
     return false;
 }
 
-// how long we hold package info before we re-fetch it
-#define PKG_EXPIRATION_NS (30*60*1000000000ll)   // 30 minutes, in nsecs
+// are we rate limited, normally false
+bool MediaAnalyticsService::isRateLimited(MediaAnalyticsItem *) const
+{
+    return false;
+}
+
+// How long we hold package info before we re-fetch it
+constexpr nsecs_t PKG_EXPIRATION_NS = 30 * 60 * NANOS_PER_SECOND; // 30 minutes
 
 // give me the package name, perhaps going to find it
 // manages its own mutex operations internally
-void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
+void MediaAnalyticsService::UidInfo::setPkgInfo(
+        MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
 {
-    ALOGV("asking for packagename to go with uid=%d", uid);
+    ALOGV("%s: uid=%d", __func__, uid);
 
     if (!setName && !setVersion) {
-        // setting nothing? strange
-        return;
+        return;  // setting nothing? strange
     }
 
-    nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
-    struct UidToPkgMap mapping;
-    mapping.uid = (uid_t)(-1);
-
+    const nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+    struct UidToPkgInfo mapping;
     {
-        Mutex::Autolock _l(mLock_mappings);
-        int i = mPkgMappings.indexOfKey(uid);
-        if (i >= 0) {
-            mapping = mPkgMappings.valueAt(i);
-            ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
-                  uid, mapping.expiration, now);
+        std::lock_guard _l(mUidInfoLock);
+        auto it = mPkgMappings.find(uid);
+        if (it != mPkgMappings.end()) {
+            mapping = it->second;
+            ALOGV("%s: uid %d expiration %lld now %lld",
+                    __func__, uid, (long long)mapping.expiration, (long long)now);
             if (mapping.expiration <= now) {
                 // purge the stale entry and fall into re-fetching
-                ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
-                mPkgMappings.removeItemsAt(i);
-                mapping.uid = (uid_t)(-1);
+                ALOGV("%s: entry for uid %d expired, now %lld",
+                        __func__, uid, (long long)now);
+                mPkgMappings.erase(it);
+                mapping.uid = (uid_t)-1;  // this is always fully overwritten
             }
         }
     }
@@ -633,115 +472,103 @@
     // if we did not find it
     if (mapping.uid == (uid_t)(-1)) {
         std::string pkg;
-        std::string installer = "";
+        std::string installer;
         int64_t versionCode = 0;
 
-        struct passwd *pw = getpwuid(uid);
+        const struct passwd *pw = getpwuid(uid);
         if (pw) {
             pkg = pw->pw_name;
         }
 
-        // find the proper value
-
-        sp<IBinder> binder = NULL;
         sp<IServiceManager> sm = defaultServiceManager();
-        if (sm == NULL) {
-            ALOGE("defaultServiceManager failed");
+        sp<content::pm::IPackageManagerNative> package_mgr;
+        if (sm.get() == nullptr) {
+            ALOGE("%s: Cannot find service manager", __func__);
         } else {
-            binder = sm->getService(String16("package_native"));
-            if (binder == NULL) {
-                ALOGE("getService package_native failed");
+            sp<IBinder> binder = sm->getService(String16("package_native"));
+            if (binder.get() == nullptr) {
+                ALOGE("%s: Cannot find package_native", __func__);
+            } else {
+                package_mgr = interface_cast<content::pm::IPackageManagerNative>(binder);
             }
         }
 
-        if (binder != NULL) {
-            sp<content::pm::IPackageManagerNative> package_mgr =
-                            interface_cast<content::pm::IPackageManagerNative>(binder);
-            binder::Status status;
-
+        if (package_mgr != nullptr) {
             std::vector<int> uids;
             std::vector<std::string> names;
-
             uids.push_back(uid);
-
-            status = package_mgr->getNamesForUids(uids, &names);
+            binder::Status status = package_mgr->getNamesForUids(uids, &names);
             if (!status.isOk()) {
-                ALOGE("package_native::getNamesForUids failed: %s",
-                      status.exceptionMessage().c_str());
-            } else {
-                if (!names[0].empty()) {
-                    pkg = names[0].c_str();
-                }
+                ALOGE("%s: getNamesForUids failed: %s",
+                        __func__, status.exceptionMessage().c_str());
+            }
+            if (!names[0].empty()) {
+                pkg = names[0].c_str();
+            }
+        }
+
+        // strip any leading "shared:" strings that came back
+        if (pkg.compare(0, 7, "shared:") == 0) {
+            pkg.erase(0, 7);
+        }
+        // determine how pkg was installed and the versionCode
+        if (pkg.empty()) {
+            pkg = std::to_string(uid); // no name for us to manage
+        } else if (strchr(pkg.c_str(), '.') == NULL) {
+            // not of form 'com.whatever...'; assume internal and ok
+        } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
+            // android.* packages are assumed fine
+        } else if (package_mgr.get() != nullptr) {
+            String16 pkgName16(pkg.c_str());
+            binder::Status status = package_mgr->getInstallerForPackage(pkgName16, &installer);
+            if (!status.isOk()) {
+                ALOGE("%s: getInstallerForPackage failed: %s",
+                        __func__, status.exceptionMessage().c_str());
             }
 
-            // strip any leading "shared:" strings that came back
-            if (pkg.compare(0, 7, "shared:") == 0) {
-                pkg.erase(0, 7);
-            }
-
-            // determine how pkg was installed and the versionCode
-            //
-            if (pkg.empty()) {
-                // no name for us to manage
-            } else if (strchr(pkg.c_str(), '.') == NULL) {
-                // not of form 'com.whatever...'; assume internal and ok
-            } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
-                // android.* packages are assumed fine
-            } else {
-                String16 pkgName16(pkg.c_str());
-                status = package_mgr->getInstallerForPackage(pkgName16, &installer);
+            // skip if we didn't get an installer
+            if (status.isOk()) {
+                status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
                 if (!status.isOk()) {
-                    ALOGE("package_native::getInstallerForPackage failed: %s",
-                          status.exceptionMessage().c_str());
-                }
-
-                // skip if we didn't get an installer
-                if (status.isOk()) {
-                    status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
-                    if (!status.isOk()) {
-                        ALOGE("package_native::getVersionCodeForPackage failed: %s",
-                          status.exceptionMessage().c_str());
-                    }
-                }
-
-
-                ALOGV("package '%s' installed by '%s' versioncode %"  PRId64 " / %" PRIx64,
-                      pkg.c_str(), installer.c_str(), versionCode, versionCode);
-
-                if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
-                        // from play store, we keep info
-                } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
-                        // some google source, we keep info
-                } else if (strcmp(installer.c_str(), "preload") == 0) {
-                        // preloads, we keep the info
-                } else if (installer.c_str()[0] == '\0') {
-                        // sideload (no installer); do not report
-                        pkg = "";
-                        versionCode = 0;
-                } else {
-                        // unknown installer; do not report
-                        pkg = "";
-                        versionCode = 0;
+                    ALOGE("%s: getVersionCodeForPackage failed: %s",
+                            __func__, status.exceptionMessage().c_str());
                 }
             }
+
+            ALOGV("%s: package '%s' installed by '%s' versioncode %lld",
+                    __func__, pkg.c_str(), installer.c_str(), (long long)versionCode);
+
+            if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
+                // from play store, we keep info
+            } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
+                // some google source, we keep info
+            } else if (strcmp(installer.c_str(), "preload") == 0) {
+                // preloads, we keep the info
+            } else if (installer.c_str()[0] == '\0') {
+                // sideload (no installer); report UID only
+                pkg = std::to_string(uid);
+                versionCode = 0;
+            } else {
+                // unknown installer; report UID only
+                pkg = std::to_string(uid);
+                versionCode = 0;
+            }
+        } else {
+            // unvalidated by package_mgr just send uid.
+            pkg = std::to_string(uid);
         }
 
         // add it to the map, to save a subsequent lookup
-        if (!pkg.empty()) {
-            Mutex::Autolock _l(mLock_mappings);
-            ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
-            ssize_t i = mPkgMappings.indexOfKey(uid);
-            if (i < 0) {
-                mapping.uid = uid;
-                mapping.pkg = pkg;
-                mapping.installer = installer.c_str();
-                mapping.versionCode = versionCode;
-                mapping.expiration = now + PKG_EXPIRATION_NS;
-                ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
-
-                mPkgMappings.add(uid, mapping);
-            }
-        }
+        std::lock_guard _l(mUidInfoLock);
+        // always overwrite
+        mapping.uid = uid;
+        mapping.pkg = std::move(pkg);
+        mapping.installer = std::move(installer);
+        mapping.versionCode = versionCode;
+        mapping.expiration = now + PKG_EXPIRATION_NS;
+        ALOGV("%s: adding uid %d pkg '%s' expiration: %lld",
+                __func__, uid, pkg.c_str(), (long long)mapping.expiration);
+        mPkgMappings[uid] = mapping;
     }
 
     if (mapping.uid != (uid_t)(-1)) {
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index 6c9cbaa..1101a8c 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -14,109 +14,99 @@
  * limitations under the License.
  */
 
+#pragma once
 
-#ifndef ANDROID_MEDIAANALYTICSSERVICE_H
-#define ANDROID_MEDIAANALYTICSSERVICE_H
-
-#include <arpa/inet.h>
-
-#include <utils/threads.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/List.h>
-
+#include <atomic>
+#include <deque>
 #include <future>
+#include <mutex>
+#include <unordered_map>
 
+// IMediaAnalyticsService must include Vector, String16, Errors
 #include <media/IMediaAnalyticsService.h>
+#include <utils/String8.h>
 
 namespace android {
 
 class MediaAnalyticsService : public BnMediaAnalyticsService
 {
+public:
+    MediaAnalyticsService();
+    ~MediaAnalyticsService() override;
 
- public:
+    // caller surrenders ownership of item, MediaAnalyticsService will delete.
+    int64_t submit(MediaAnalyticsItem *item, bool forcenew) override;
 
-    // on this side, caller surrenders ownership
-    virtual int64_t submit(MediaAnalyticsItem *item, bool forcenew);
+    status_t dump(int fd, const Vector<String16>& args) override;
 
-    static  void            instantiate();
-    virtual status_t        dump(int fd, const Vector<String16>& args);
+    static constexpr const char * const kServiceName = "media.metrics";
 
-                            MediaAnalyticsService();
-    virtual                 ~MediaAnalyticsService();
-
-    bool processExpirations();
-
- private:
+private:
+    void processExpirations();
     MediaAnalyticsItem::SessionID_t generateUniqueSessionID();
+    // input validation after arrival from client
+    static bool isContentValid(const MediaAnalyticsItem *item, bool isTrusted);
+    bool isRateLimited(MediaAnalyticsItem *) const;
+    void saveItem(MediaAnalyticsItem *);
 
-    // statistics about our analytics
-    int64_t mItemsSubmitted;
-    int64_t mItemsFinalized;
-    int64_t mItemsDiscarded;
-    int64_t mItemsDiscardedExpire;
-    int64_t mItemsDiscardedCount;
-    MediaAnalyticsItem::SessionID_t mLastSessionID;
+    // The following methods are GUARDED_BY(mLock)
+    bool expirations_l(MediaAnalyticsItem *);
 
-    // partitioned a bit so we don't over serialize
-    mutable Mutex           mLock;
-    mutable Mutex           mLock_ids;
-    mutable Mutex           mLock_mappings;
+    // support for generating output
+    void dumpQueue_l(String8 &result, int dumpProto);
+    void dumpQueue_l(String8 &result, int dumpProto, nsecs_t, const char *only);
+    void dumpHeaders_l(String8 &result, int dumpProto, nsecs_t ts_since);
+    void dumpSummaries_l(String8 &result, int dumpProto, nsecs_t ts_since, const char * only);
+    void dumpRecent_l(String8 &result, int dumpProto, nsecs_t ts_since, const char * only);
+
+    // The following variables accessed without mLock
 
     // limit how many records we'll retain
     // by count (in each queue (open, finalized))
-    int32_t mMaxRecords;
-    // by time (none older than this long agan
-    nsecs_t mMaxRecordAgeNs;
+    const size_t mMaxRecords;
+    // by time (none older than this)
+    const nsecs_t mMaxRecordAgeNs;
     // max to expire per expirations_l() invocation
-    int32_t mMaxRecordsExpiredAtOnce;
-    //
-    // # of sets of summaries
-    int32_t mMaxRecordSets;
-    // nsecs until we start a new record set
-    nsecs_t mNewSetInterval;
+    const size_t mMaxRecordsExpiredAtOnce;
+    const int mDumpProtoDefault;
 
-    // input validation after arrival from client
-    bool contentValid(MediaAnalyticsItem *item, bool isTrusted);
-    bool rateLimited(MediaAnalyticsItem *);
+    std::atomic<MediaAnalyticsItem::SessionID_t> mLastSessionID{};
 
-    // (oldest at front) so it prints nicely for dumpsys
-    List<MediaAnalyticsItem *> mItems;
-    void saveItem(MediaAnalyticsItem *);
+    class UidInfo {
+    public:
+        void setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion);
 
-    bool expirations_l(MediaAnalyticsItem *);
-    std::future<bool> mExpireFuture;
+    private:
+        std::mutex mUidInfoLock;
 
-    // support for generating output
-    int mDumpProto;
-    int mDumpProtoDefault;
-    String8 dumpQueue();
-    String8 dumpQueue(nsecs_t, const char *only);
+        struct UidToPkgInfo {
+            uid_t uid = -1;
+            std::string pkg;
+            std::string installer;
+            int64_t versionCode = 0;
+            nsecs_t expiration = 0;  // TODO: remove expiration.
+        };
 
-    void dumpHeaders(String8 &result, nsecs_t ts_since);
-    void dumpSummaries(String8 &result, nsecs_t ts_since, const char * only);
-    void dumpRecent(String8 &result, nsecs_t ts_since, const char * only);
+        // TODO: use concurrent hashmap with striped lock.
+        std::unordered_map<uid_t, struct UidToPkgInfo> mPkgMappings; // GUARDED_BY(mUidInfoLock)
+    } mUidInfo;  // mUidInfo can be accessed without lock (locked internally)
 
-    // mapping uids to package names
-    struct UidToPkgMap {
-        uid_t uid;
-        std::string pkg;
-        std::string installer;
-        int64_t versionCode;
-        nsecs_t expiration;
-    };
+    std::atomic<int64_t> mItemsSubmitted{}; // accessed outside of lock.
 
-    KeyedVector<uid_t,struct UidToPkgMap>  mPkgMappings;
-    void setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion);
+    std::mutex mLock;
+    // statistics about our analytics
+    int64_t mItemsFinalized = 0;        // GUARDED_BY(mLock)
+    int64_t mItemsDiscarded = 0;        // GUARDED_BY(mLock)
+    int64_t mItemsDiscardedExpire = 0;  // GUARDED_BY(mLock)
+    int64_t mItemsDiscardedCount = 0;   // GUARDED_BY(mLock)
 
+    // If we have a worker thread to garbage collect
+    std::future<void> mExpireFuture;    // GUARDED_BY(mLock)
+
+    // Our item queue, generally (oldest at front)
+    // TODO: Make separate class, use segmented queue, write lock only end.
+    // Note: Another analytics module might have ownership of an item longer than the log.
+    std::deque<std::shared_ptr<const MediaAnalyticsItem>> mItems; // GUARDED_BY(mLock)
 };
 
-// hook to send things off to the statsd subsystem
-extern bool dump2Statsd(MediaAnalyticsItem *item);
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_MEDIAANALYTICSSERVICE_H
+} // namespace android
diff --git a/services/mediaanalytics/OWNERS b/services/mediaanalytics/OWNERS
index 9af258b..e37a1f8 100644
--- a/services/mediaanalytics/OWNERS
+++ b/services/mediaanalytics/OWNERS
@@ -1 +1,2 @@
 essick@google.com
+hunga@google.com
diff --git a/services/mediaanalytics/iface_statsd.cpp b/services/mediaanalytics/iface_statsd.cpp
index 6fd4415..e02c9cf 100644
--- a/services/mediaanalytics/iface_statsd.cpp
+++ b/services/mediaanalytics/iface_statsd.cpp
@@ -52,7 +52,7 @@
 };
 
 // keep this sorted, so we can do binary searches
-struct statsd_hooks  statsd_handlers[] =
+static constexpr struct statsd_hooks statsd_handlers[] =
 {
     { "audiopolicy", statsd_audiopolicy },
     { "audiorecord", statsd_audiorecord },
@@ -68,7 +68,6 @@
     { "recorder", statsd_recorder },
 };
 
-
 // give me a record, i'll look at the type and upload appropriately
 bool dump2Statsd(MediaAnalyticsItem *item) {
     if (item == NULL) return false;
@@ -81,10 +80,9 @@
         return false;
     }
 
-    int i;
-    for(i = 0;i < sizeof(statsd_handlers) / sizeof(statsd_handlers[0]) ; i++) {
-        if (key == statsd_handlers[i].key) {
-            return (*statsd_handlers[i].handler)(item);
+    for (const auto &statsd_handler : statsd_handlers) {
+        if (key == statsd_handler.key) {
+            return statsd_handler.handler(item);
         }
     }
     return false;
diff --git a/services/mediaanalytics/main_mediametrics.cpp b/services/mediaanalytics/main_mediametrics.cpp
index 8020a03..6833fe2 100644
--- a/services/mediaanalytics/main_mediametrics.cpp
+++ b/services/mediaanalytics/main_mediametrics.cpp
@@ -16,33 +16,33 @@
 
 #define LOG_TAG "mediametrics"
 //#define LOG_NDEBUG 0
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
 #include <utils/Log.h>
-//#include "RegisterExtensions.h"
 
-// from LOCAL_C_INCLUDES
 #include "MediaAnalyticsService.h"
 
-using namespace android;
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
 
 int main(int argc __unused, char **argv __unused)
 {
+    using namespace android;
+
     signal(SIGPIPE, SIG_IGN);
 
     // to match the service name
     // we're replacing "/system/bin/mediametrics" with "media.metrics"
     // we add a ".", but discard the path components: we finish with a shorter string
-    strcpy(argv[0], "media.metrics");
+    strcpy(argv[0], MediaAnalyticsService::kServiceName);
 
-    sp<ProcessState> proc(ProcessState::self());
-    sp<IServiceManager> sm(defaultServiceManager());
-    ALOGI("ServiceManager: %p", sm.get());
+    defaultServiceManager()->addService(
+            String16(MediaAnalyticsService::kServiceName), new MediaAnalyticsService());
 
-    MediaAnalyticsService::instantiate();
-
-    ProcessState::self()->startThreadPool();
+    sp<ProcessState> processState(ProcessState::self());
+    // processState->setThreadPoolMaxThreadCount(8);
+    processState->startThreadPool();
     IPCThreadState::self()->joinThreadPool();
+
+    return EXIT_SUCCESS;
 }