Clean up how we handle configurations, and other assorted cleanup

- Add a ConfigManager class that tracks the configurations
  that have been passed to us.  Configurations are now
  tracked by tuples of (uid,tag), where the tag is an
  app-defined string, in case a single uid has multiple
  configurations.
- Move all of the initialization into StatsService.
- Get rid of the ability to have multiple LogListeners. Raw
  events are now pushed directly into StatsService, which
  can distribute them to the interested parties (and will
  eventually be able to do the proper locking).
- Add Log.h, which sets our LOG_TAG correctly.
- Move some of the related files that I expect will grow some
  into their own subdirectories.

Test: statsd_test
Test: adb shell cmd stats config ...
Test: adb shell dumpsys stats
Change-Id: I79487603003d8a842d5bd319741f1ecbf72063d1
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 7412d18..a8d3e12 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -14,16 +14,23 @@
 
 LOCAL_PATH:= $(call my-dir)
 
-
 statsd_common_src := \
     ../../core/java/android/os/IStatsCompanionService.aidl \
     ../../core/java/android/os/IStatsManager.aidl \
     src/stats_log.proto \
     src/statsd_config.proto \
     src/stats_events_copy.proto \
+    src/anomaly/AnomalyMonitor.cpp \
     src/condition/CombinationConditionTracker.cpp \
     src/condition/condition_util.cpp \
     src/condition/SimpleConditionTracker.cpp \
+    src/config/ConfigKey.cpp \
+    src/config/ConfigListener.cpp \
+    src/config/ConfigManager.cpp \
+    src/external/KernelWakelockPuller.cpp \
+    src/external/StatsPullerManager.cpp \
+    src/logd/LogListener.cpp \
+    src/logd/LogReader.cpp \
     src/matchers/CombinationLogMatchingTracker.cpp \
     src/matchers/matcher_util.cpp \
     src/matchers/SimpleLogMatchingTracker.cpp \
@@ -31,17 +38,12 @@
     src/metrics/CountMetricProducer.cpp \
     src/metrics/MetricsManager.cpp \
     src/metrics/metrics_manager_util.cpp \
-    src/AnomalyMonitor.cpp \
-    src/DropboxReader.cpp \
-    src/DropboxWriter.cpp \
-    src/KernelWakelockPuller.cpp \
-    src/LogEntryPrinter.cpp \
-    src/LogReader.cpp \
+    src/packages/UidMap.cpp \
+    src/storage/DropboxReader.cpp \
+    src/storage/DropboxWriter.cpp \
     src/StatsLogProcessor.cpp \
-    src/StatsPullerManager.cpp \
     src/StatsService.cpp \
-    src/stats_util.cpp \
-    src/UidMap.cpp
+    src/stats_util.cpp
 
 statsd_common_c_includes := \
     $(LOCAL_PATH)/src
@@ -125,13 +127,15 @@
 
 LOCAL_SRC_FILES := \
     $(statsd_common_src) \
+    tests/AnomalyMonitor_test.cpp \
+    tests/ConditionTracker_test.cpp \
+    tests/ConfigManager_test.cpp \
     tests/indexed_priority_queue_test.cpp \
+    tests/LogEntryMatcher_test.cpp \
     tests/LogReader_test.cpp \
     tests/MetricsManager_test.cpp \
-    tests/UidMap_test.cpp \
-    tests/LogEntryMatcher_test.cpp \
-    tests/AnomalyMonitor_test.cpp \
-    tests/ConditionTracker_test.cpp
+    tests/UidMap_test.cpp
+
 
 LOCAL_STATIC_LIBRARIES := \
     libgmock
diff --git a/cmds/statsd/src/Log.h b/cmds/statsd/src/Log.h
new file mode 100644
index 0000000..7852709
--- /dev/null
+++ b/cmds/statsd/src/Log.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*
+ * This file must be included at the top of the file. Other header files
+ * occasionally include log.h, and if LOG_TAG isn't set when that happens
+ * we'll get a preprocesser error when we try to define it here.
+ */
+
+#pragma once
+
+#define LOG_TAG "statsd"
+
+#include <log/log.h>
+
+#define VLOG(...) \
+    if (DEBUG) ALOGD(__VA_ARGS__);
diff --git a/cmds/statsd/src/LogEntryPrinter.cpp b/cmds/statsd/src/LogEntryPrinter.cpp
deleted file mode 100644
index 3b6f679..0000000
--- a/cmds/statsd/src/LogEntryPrinter.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2017 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 <LogEntryPrinter.h>
-
-#include <log/event_tag_map.h>
-#include <log/logprint.h>
-#include <utils/Errors.h>
-
-#include "matchers/matcher_util.h"
-
-#define PRINT_WITH_LIBLOG 0
-#define PRINT_WITH_LOG_EVENT_WRAPPER 1
-
-using namespace android;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-LogEntryPrinter::LogEntryPrinter(int out) : m_out(out) {
-    // Initialize the EventTagMap, which is how we know the names of the numeric event tags.
-    // If this fails, we can't print well, but something will print.
-    m_tags = android_openEventTagMap(NULL);
-
-    // Printing format
-    m_format = android_log_format_new();
-    android_log_setPrintFormat(m_format, FORMAT_THREADTIME);
-}
-
-LogEntryPrinter::~LogEntryPrinter() {
-    if (m_tags != NULL) {
-        android_closeEventTagMap(m_tags);
-    }
-    android_log_format_free(m_format);
-}
-
-void LogEntryPrinter::OnLogEvent(const log_msg& msg) {
-    if (PRINT_WITH_LIBLOG) {
-        status_t err;
-        AndroidLogEntry entry;
-        char buf[1024];
-
-        err = android_log_processBinaryLogBuffer(&(const_cast<log_msg*>(&msg)->entry_v1), &entry,
-                                                 m_tags, buf, sizeof(buf));
-        if (err == NO_ERROR) {
-            android_log_printLogLine(m_format, m_out, &entry);
-        } else {
-            printf("log entry: %s\n", buf);
-            fflush(stdout);
-        }
-    }
-
-    if (PRINT_WITH_LOG_EVENT_WRAPPER) {
-        LogEventWrapper event = parseLogEvent(msg);
-        printf("event: %s\n", event.toString().c_str());
-        fflush(stdout);
-    }
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/LogEntryPrinter.h b/cmds/statsd/src/LogEntryPrinter.h
deleted file mode 100644
index 4f79028..0000000
--- a/cmds/statsd/src/LogEntryPrinter.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2017 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 LOG_ENTRY_PRINTER_H
-#define LOG_ENTRY_PRINTER_H
-
-#include "LogReader.h"
-
-#include <log/logprint.h>
-
-#include <stdio.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Decodes the log entry and prints it to the supplied file descriptor.
- */
-class LogEntryPrinter : public LogListener {
-public:
-    LogEntryPrinter(int out);
-    virtual ~LogEntryPrinter();
-
-    virtual void OnLogEvent(const log_msg& msg);
-
-private:
-    /**
-     * Where to write to.
-     */
-    int m_out;
-
-    /**
-     * Numeric to string tag name mapping.
-     */
-    EventTagMap* m_tags;
-
-    /**
-     * Pretty printing format.
-     */
-    AndroidLogFormat* m_format;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
-
-#endif  // LOG_ENTRY_PRINTER_H
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index f877ef3..1308ca1 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
-#include <StatsLogProcessor.h>
+#include "Log.h"
 
-#include <cutils/log.h>
-#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
+#include "StatsLogProcessor.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "metrics/CountMetricProducer.h"
+#include "stats_util.h"
+
 #include <log/log_event_list.h>
-#include <metrics/CountMetricProducer.h>
 #include <utils/Errors.h>
 
 using namespace android;
@@ -31,12 +33,8 @@
 namespace os {
 namespace statsd {
 
-StatsLogProcessor::StatsLogProcessor(const sp<UidMap> &uidMap)
-        : m_dropbox_writer("all-logs"), m_UidMap(uidMap)
-{
-    // hardcoded config
-    // this should be called from StatsService when it receives a statsd_config
-    UpdateConfig(0, buildFakeConfig());
+StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap)
+    : m_dropbox_writer("all-logs"), mUidMap(uidMap) {
 }
 
 StatsLogProcessor::~StatsLogProcessor() {
@@ -54,17 +52,18 @@
     }
 }
 
-void StatsLogProcessor::UpdateConfig(const int config_source, const StatsdConfig& config) {
-    auto it = mMetricsManagers.find(config_source);
+void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
+    auto it = mMetricsManagers.find(key);
     if (it != mMetricsManagers.end()) {
         it->second->finish();
     }
 
-    ALOGD("Updated configuration for source %i", config_source);
+    ALOGD("Updated configuration for key %s", key.ToString().c_str());
 
     unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(config);
     if (newMetricsManager->isConfigValid()) {
-        mMetricsManagers.insert({config_source, std::move(newMetricsManager)});
+        mMetricsManagers[key] = std::move(newMetricsManager);
+        // Why doesn't this work? mMetricsManagers.insert({key, std::move(newMetricsManager)});
         ALOGD("StatsdConfig valid");
     } else {
         // If there is any error in the config, don't use it.
@@ -72,6 +71,14 @@
     }
 }
 
+void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
+    auto it = mMetricsManagers.find(key);
+    if (it != mMetricsManagers.end()) {
+        it->second->finish();
+        mMetricsManagers.erase(it);
+    }
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 05e441c..6f5dd04 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -16,12 +16,13 @@
 #ifndef STATS_LOG_PROCESSOR_H
 #define STATS_LOG_PROCESSOR_H
 
-#include "DropboxWriter.h"
-#include "LogReader.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "config/ConfigListener.h"
+#include "logd/LogReader.h"
 #include "metrics/MetricsManager.h"
-#include "stats_util.h"
-#include "UidMap.h"
+#include "packages/UidMap.h"
+#include "storage/DropboxWriter.h"
+
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 #include <log/logprint.h>
 #include <stdio.h>
@@ -31,22 +32,23 @@
 namespace os {
 namespace statsd {
 
-class StatsLogProcessor : public LogListener {
+class StatsLogProcessor : public ConfigListener {
 public:
     StatsLogProcessor(const sp<UidMap> &uidMap);
     virtual ~StatsLogProcessor();
 
     virtual void OnLogEvent(const log_msg& msg);
 
-    void UpdateConfig(const int config_source, const StatsdConfig& config);
+    void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
+    void OnConfigRemoved(const ConfigKey& key);
 
 private:
     // TODO: use EventMetrics to log the events.
     DropboxWriter m_dropbox_writer;
 
-    std::unordered_map<int, std::unique_ptr<MetricsManager>> mMetricsManagers;
+    std::unordered_map<ConfigKey, std::unique_ptr<MetricsManager>> mMetricsManagers;
 
-    sp<UidMap> m_UidMap; // Reference to the UidMap to lookup app name and version for each uid.
+    sp<UidMap> mUidMap;  // Reference to the UidMap to lookup app name and version for each uid.
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index b496404..eff2c1c 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "statsd"
 #define DEBUG true
+#include "Log.h"
 
 #include "StatsService.h"
-#include "DropboxReader.h"
+#include "storage/DropboxReader.h"
 
 #include <android-base/file.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
-#include <cutils/log.h>
 #include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
 #include <private/android_filesystem_config.h>
 #include <utils/Looper.h>
@@ -31,6 +30,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/system_properties.h>
 #include <unistd.h>
 
 using namespace android;
@@ -39,24 +39,65 @@
 namespace os {
 namespace statsd {
 
+// ======================================================================
+/**
+ * Watches for the death of the stats companion (system process).
+ */
+class CompanionDeathRecipient : public IBinder::DeathRecipient {
+public:
+    CompanionDeathRecipient(const sp<AnomalyMonitor>& anomalyMonitor);
+    virtual void binderDied(const wp<IBinder>& who);
+
+private:
+    const sp<AnomalyMonitor> mAnomalyMonitor;
+};
+
+CompanionDeathRecipient::CompanionDeathRecipient(const sp<AnomalyMonitor>& anomalyMonitor)
+    : mAnomalyMonitor(anomalyMonitor) {
+}
+
+void CompanionDeathRecipient::binderDied(const wp<IBinder>& who) {
+    ALOGW("statscompanion service died");
+    mAnomalyMonitor->setStatsCompanionService(nullptr);
+}
+
+// ======================================================================
 StatsService::StatsService(const sp<Looper>& handlerLooper)
-    :   mAnomalyMonitor(new AnomalyMonitor(2)),m_UidMap(new UidMap()), mStatsPullerManager()
-    // TODO: Change AnomalyMonitor initialization based on the config
+    : mStatsPullerManager(),
+
+      mAnomalyMonitor(new AnomalyMonitor(2))  // TODO: Put this comment somewhere better
 {
-    ALOGD("stats service constructed");
+    mUidMap = new UidMap();
+    mConfigManager = new ConfigManager();
+    mProcessor = new StatsLogProcessor(mUidMap);
+
+    mConfigManager->AddListener(mProcessor);
+
+    init_system_properties();
 }
 
 StatsService::~StatsService() {
 }
 
-status_t StatsService::setProcessor(const sp<StatsLogProcessor>& main_processor) {
-    m_processor = main_processor;
-    ALOGD("stats service set to processor %p", m_processor.get());
-    return NO_ERROR;
+void StatsService::init_system_properties() {
+    mEngBuild = false;
+    const prop_info* buildType = __system_property_find("ro.build.type");
+    if (buildType != NULL) {
+        __system_property_read_callback(buildType, init_build_type_callback, this);
+    }
 }
 
-// Implement our own because the default binder implementation isn't
-// properly handling SHELL_COMMAND_TRANSACTION
+void StatsService::init_build_type_callback(void* cookie, const char* /*name*/, const char* value,
+                                            uint32_t serial) {
+    if (0 == strcmp("eng", value)) {
+        reinterpret_cast<StatsService*>(cookie)->mEngBuild = true;
+    }
+}
+
+/**
+ * Implement our own because the default binder implementation isn't
+ * properly handling SHELL_COMMAND_TRANSACTION.
+ */
 status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                   uint32_t flags) {
     status_t err;
@@ -105,56 +146,159 @@
     }
 }
 
+/**
+ * Write debugging data about statsd.
+ */
 status_t StatsService::dump(int fd, const Vector<String16>& args) {
     FILE* out = fdopen(fd, "w");
     if (out == NULL) {
         return NO_MEMORY;  // the fd is already open
     }
 
-    fprintf(out, "StatsService::dump:");
-    ALOGD("StatsService::dump:");
-    const int N = args.size();
-    for (int i = 0; i < N; i++) {
-        fprintf(out, " %s", String8(args[i]).string());
-        ALOGD("   %s", String8(args[i]).string());
-    }
-    fprintf(out, "\n");
+    // TODO: Proto format for incident reports
+    dump_impl(out);
 
     fclose(out);
     return NO_ERROR;
 }
 
+/**
+ * Write debugging data about statsd in text format.
+ */
+void StatsService::dump_impl(FILE* out) {
+    mConfigManager->Dump(out);
+}
+
+/**
+ * Implementation of the adb shell cmd stats command.
+ */
 status_t StatsService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
-    if (args.size() > 0) {
-        if (!args[0].compare(String8("print-stats-log")) && args.size() > 1) {
-            return doPrintStatsLog(out, args);
-        }
+    // TODO: Permission check
+
+    const int argCount = args.size();
+    if (argCount >= 1) {
+        // adb shell cmd stats config ...
         if (!args[0].compare(String8("config"))) {
-            return doLoadConfig(in);
+            return cmd_config(in, out, err, args);
         }
+
+        // adb shell cmd stats print-stats-log
+        if (!args[0].compare(String8("print-stats-log")) && args.size() > 1) {
+            return cmd_print_stats_log(out, args);
+        }
+
+        // adb shell cmd stats print-stats-log
         if (!args[0].compare(String8("print-uid-map"))) {
-            return doPrintUidMap(out);
+            return cmd_print_uid_map(out);
         }
     }
 
-    printCmdHelp(out);
+    print_cmd_help(out);
     return NO_ERROR;
 }
 
-status_t StatsService::doLoadConfig(FILE* in) {
-    string content;
-    if (!android::base::ReadFdToString(fileno(in), &content)) {
-        return UNKNOWN_ERROR;
+void StatsService::print_cmd_help(FILE* out) {
+    fprintf(out,
+            "usage: adb shell cmd stats print-stats-log [tag_required] "
+            "[timestamp_nsec_optional]\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
+    fprintf(out, "usage: adb shell cmd stats print-uid-map \n");
+    fprintf(out, "\n");
+    fprintf(out, "  Prints the UID, app name, version mapping.\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
+    fprintf(out, "usage: adb shell cmd stats config remove [UID] NAME\n");
+    fprintf(out, "usage: adb shell cmd stats config update [UID] NAME\n");
+    fprintf(out, "\n");
+    fprintf(out, "  Adds, updates or removes a configuration. The proto should be in\n");
+    fprintf(out, "  wire-encoded protobuf format and passed via stdin.\n");
+    fprintf(out, "\n");
+    fprintf(out, "  UID           The uid to use. It is only possible to pass the UID\n");
+    fprintf(out, "                parameter on eng builds.  If UID is omitted the calling\n");
+    fprintf(out, "                uid is used.\n");
+    fprintf(out, "  NAME          The per-uid name to use\n");
+}
+
+status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+    const int argCount = args.size();
+    if (argCount >= 2) {
+        if (args[1] == "update" || args[1] == "remove") {
+            bool good = false;
+            int uid = -1;
+            string name;
+
+            if (argCount == 3) {
+                // Automatically pick the UID
+                uid = IPCThreadState::self()->getCallingUid();
+                // TODO: What if this isn't a binder call? Should we fail?
+                name.assign(args[2].c_str(), args[2].size());
+                good = true;
+            } else if (argCount == 4) {
+                // If it's a userdebug or eng build, then the shell user can
+                // impersonate other uids.
+                if (mEngBuild) {
+                    const char* s = args[2].c_str();
+                    if (*s != '\0') {
+                        char* end = NULL;
+                        uid = strtol(s, &end, 0);
+                        if (*end == '\0') {
+                            name.assign(args[3].c_str(), args[3].size());
+                            good = true;
+                        }
+                    }
+                } else {
+                    fprintf(err, "The config can only be set for other UIDs on eng builds.\n");
+                }
+            }
+
+            if (!good) {
+                // If arg parsing failed, print the help text and return an error.
+                print_cmd_help(out);
+                return UNKNOWN_ERROR;
+            }
+
+            if (args[1] == "update") {
+                // Read stream into buffer.
+                string buffer;
+                if (!android::base::ReadFdToString(fileno(in), &buffer)) {
+                    fprintf(err, "Error reading stream for StatsConfig.\n");
+                    return UNKNOWN_ERROR;
+                }
+
+                // Parse buffer.
+                StatsdConfig config;
+                if (!config.ParseFromString(buffer)) {
+                    fprintf(err, "Error parsing proto stream for StatsConfig.\n");
+                    return UNKNOWN_ERROR;
+                }
+
+                // Add / update the config.
+                mConfigManager->UpdateConfig(ConfigKey(uid, name), config);
+            } else {
+                // Remove the config.
+                mConfigManager->RemoveConfig(ConfigKey(uid, name));
+            }
+
+            return NO_ERROR;
+        }
     }
-    StatsdConfig config;
-    if (config.ParseFromString(content)) {
-        ALOGD("Config parsed from command line: %s", config.SerializeAsString().c_str());
-        m_processor->UpdateConfig(0, config);
-        return NO_ERROR;
-    } else {
-        ALOGD("Config failed to be parsed");
-        return UNKNOWN_ERROR;
+    print_cmd_help(out);
+    return UNKNOWN_ERROR;
+}
+
+status_t StatsService::cmd_print_stats_log(FILE* out, const Vector<String8>& args) {
+    long msec = 0;
+
+    if (args.size() > 2) {
+        msec = strtol(args[2].string(), NULL, 10);
     }
+    return DropboxReader::readStatsLogs(out, args[1].string(), msec);
+}
+
+status_t StatsService::cmd_print_uid_map(FILE* out) {
+    mUidMap->printUidMap(out);
+    return NO_ERROR;
 }
 
 Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
@@ -166,7 +310,7 @@
                                          "Only system uid can call informAllUidData");
     }
 
-    m_UidMap->updateMap(uid, version, app);
+    mUidMap->updateMap(uid, version, app);
     if (DEBUG) ALOGD("StatsService::informAllUidData succeeded");
 
     return Status::ok();
@@ -179,7 +323,7 @@
         return Status::fromExceptionCode(Status::EX_SECURITY,
                                          "Only system uid can call informOnePackage");
     }
-    m_UidMap->updateApp(app, uid, version);
+    mUidMap->updateApp(app, uid, version);
     return Status::ok();
 }
 
@@ -190,7 +334,7 @@
         return Status::fromExceptionCode(Status::EX_SECURITY,
                                          "Only system uid can call informOnePackageRemoved");
     }
-    m_UidMap->removeApp(app, uid);
+    mUidMap->removeApp(app, uid);
     return Status::ok();
 }
 
@@ -282,38 +426,18 @@
                 "statscompanion unavailable despite it contacting statsd!");
     }
     if (DEBUG) ALOGD("StatsService::statsCompanionReady linking to statsCompanion.");
-    IInterface::asBinder(statsCompanion)->linkToDeath(new StatsdDeathRecipient(mAnomalyMonitor));
+    IInterface::asBinder(statsCompanion)->linkToDeath(new CompanionDeathRecipient(mAnomalyMonitor));
     mAnomalyMonitor->setStatsCompanionService(statsCompanion);
 
     return Status::ok();
 }
 
-void StatsdDeathRecipient::binderDied(const wp<IBinder>& who) {
-    ALOGW("statscompanion service died");
-    mAnmlyMntr->setStatsCompanionService(nullptr);
+void StatsService::Startup() {
+    mConfigManager->Startup();
 }
 
-status_t StatsService::doPrintStatsLog(FILE* out, const Vector<String8>& args) {
-    long msec = 0;
-
-    if (args.size() > 2) {
-        msec = strtol(args[2].string(), NULL, 10);
-    }
-    return DropboxReader::readStatsLogs(out, args[1].string(), msec);
-}
-
-status_t StatsService::doPrintUidMap(FILE* out) {
-    m_UidMap->printUidMap(out);
-    return NO_ERROR;
-}
-
-void StatsService::printCmdHelp(FILE* out) {
-    fprintf(out, "Usage:\n");
-    fprintf(out, "\t print-stats-log [tag_required] [timestamp_nsec_optional]\n");
-    fprintf(out, "\t print-uid-map Prints the UID, app name, version mapping.\n");
-    fprintf(out,
-            "\t config\t Loads a new config from command-line (must be proto in wire-encoded "
-            "format).\n");
+void StatsService::OnLogEvent(const log_msg& msg) {
+    mProcessor->OnLogEvent(msg);
 }
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 541f7e8..dcc73a1 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -17,11 +17,11 @@
 #ifndef STATS_SERVICE_H
 #define STATS_SERVICE_H
 
-#include "AnomalyMonitor.h"
 #include "StatsLogProcessor.h"
-#include "StatsPullerManager.h"
-#include "StatsPuller.h"
-#include "UidMap.h"
+#include "anomaly/AnomalyMonitor.h"
+#include "config/ConfigManager.h"
+#include "external/StatsPullerManager.h"
+#include "packages/UidMap.h"
 
 #include <android/os/BnStatsManager.h>
 #include <android/os/IStatsCompanionService.h>
@@ -42,75 +42,114 @@
 namespace os {
 namespace statsd {
 
-class StatsService : public BnStatsManager {
+class StatsService : public BnStatsManager, public LogListener {
 public:
     StatsService(const sp<Looper>& handlerLooper);
     virtual ~StatsService();
 
     virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
-
     virtual status_t dump(int fd, const Vector<String16>& args);
-
     virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
 
     virtual Status systemRunning();
-
-    // Inform statsd that statsCompanion is ready.
     virtual Status statsCompanionReady();
-
     virtual Status informAnomalyAlarmFired();
-
     virtual Status informPollAlarmFired();
-
     virtual Status informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
                                     const vector<String16>& app);
     virtual Status informOnePackage(const String16& app, int32_t uid, int32_t version);
     virtual Status informOnePackageRemoved(const String16& app, int32_t uid);
 
-    virtual status_t setProcessor(const sp<StatsLogProcessor>& main_processor);
+    /**
+     * Called right before we start processing events.
+     */
+    void Startup();
+
+    /**
+     * Called by LogReader when there's a log event to process.
+     */
+    virtual void OnLogEvent(const log_msg& msg);
 
     // TODO: public for testing since statsd doesn't run when system starts. Change to private
     // later.
     /** Inform statsCompanion that statsd is ready. */
     virtual void sayHiToStatsCompanion();
 
-    // TODO: Move this to a more logical file/class
-    // TODO: Should be private. Temporarily public for testing purposes only.
-    const sp<AnomalyMonitor> mAnomalyMonitor;
-
-    sp<UidMap> getUidMap() {
-        return m_UidMap;
-    }
-
     /** Fetches and returns the StatsCompanionService. */
     static sp<IStatsCompanionService> getStatsCompanionService();
 
 private:
-    sp<UidMap> m_UidMap; // Reference to the UID map needed for translating UID to app name/version.
+    /**
+     * Load system properties at init.
+     */
+    void init_system_properties();
 
-    sp<StatsLogProcessor> m_processor;  // Reference to the processor for updating configs.
+    /**
+     * Helper for loading system properties.
+     */
+    static void init_build_type_callback(void* cookie, const char* name, const char* value,
+                                         uint32_t serial);
 
-    status_t doPrintStatsLog(FILE* out, const Vector<String8>& args);
+    /**
+     * Text output of dumpsys.
+     */
+    void dump_impl(FILE* out);
 
-    void printCmdHelp(FILE* out);
+    /**
+     * Print usage information for the commands
+     */
+    void print_cmd_help(FILE* out);
 
-    status_t doLoadConfig(FILE* in);
+    /**
+     * Handle the config sub-command.
+     */
+    status_t cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
 
+    /**
+     * Print the event log.
+     */
+    status_t cmd_print_stats_log(FILE* out, const Vector<String8>& args);
+
+    /**
+     * Print the mapping of uids to package names.
+     */
+    status_t cmd_print_uid_map(FILE* out);
+
+    /**
+     * Update a configuration.
+     */
+    void set_config(int uid, const string& name, const StatsdConfig& config);
+
+    /**
+     * Tracks the uid <--> package name mapping.
+     */
+    sp<UidMap> mUidMap;
+
+    /**
+     * Fetches external metrics.
+     * TODO: This should be an sp<>
+     */
     StatsPullerManager mStatsPullerManager;
 
-    status_t doPrintUidMap(FILE* out);
-};
+    /**
+     * Tracks the configurations that have been passed to statsd.
+     */
+    sp<ConfigManager> mConfigManager;
 
-// --- StatsdDeathRecipient ---
-class StatsdDeathRecipient : public IBinder::DeathRecipient {
-public:
-    StatsdDeathRecipient(sp<AnomalyMonitor> anomalyMonitor) : mAnmlyMntr(anomalyMonitor) {
-    }
+    /**
+     * The metrics recorder.
+     */
+    sp<StatsLogProcessor> mProcessor;
 
-    virtual void binderDied(const wp<IBinder>& who);
+    /**
+     * The anomaly detector.
+     */
+    const sp<AnomalyMonitor> mAnomalyMonitor;
 
-private:
-    const sp<AnomalyMonitor> mAnmlyMntr;
+    /**
+     * Whether this is an eng build.
+     */
+    bool mEngBuild;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
similarity index 91%
rename from cmds/statsd/src/AnomalyMonitor.cpp
rename to cmds/statsd/src/anomaly/AnomalyMonitor.cpp
index 4fbbc7a..7a46410 100644
--- a/cmds/statsd/src/AnomalyMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
@@ -14,12 +14,10 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "AnomalyMonitor"
 #define DEBUG true
+#include "Log.h"
 
-#include "AnomalyMonitor.h"
-
-#include <cutils/log.h>
+#include "anomaly/AnomalyMonitor.h"
 
 namespace android {
 namespace os {
@@ -92,17 +90,16 @@
 
 // More efficient than repeatedly calling remove(mPq.top()) since it batches the
 // updates to the registered alarm.
-unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>
-                AnomalyMonitor::popSoonerThan(uint32_t timestampSec) {
-
+unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> AnomalyMonitor::popSoonerThan(
+        uint32_t timestampSec) {
     if (DEBUG) ALOGD("Removing alarms with time <= %u", timestampSec);
     unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> oldAlarms;
     std::lock_guard<std::mutex> lock(mLock);
 
-    for (sp<const AnomalyAlarm> t = mPq.top();
-                t != nullptr && t->timestampSec <= timestampSec; t = mPq.top()) {
+    for (sp<const AnomalyAlarm> t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec;
+         t = mPq.top()) {
         oldAlarms.insert(t);
-        mPq.pop(); // remove t
+        mPq.pop();  // remove t
     }
     // Always update registered alarm time (if anything has changed).
     if (!oldAlarms.empty()) {
diff --git a/cmds/statsd/src/AnomalyMonitor.h b/cmds/statsd/src/anomaly/AnomalyMonitor.h
similarity index 96%
rename from cmds/statsd/src/AnomalyMonitor.h
rename to cmds/statsd/src/anomaly/AnomalyMonitor.h
index 7c6e5e8..e2ac623 100644
--- a/cmds/statsd/src/AnomalyMonitor.h
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.h
@@ -17,12 +17,13 @@
 #ifndef ANOMALY_MONITOR_H
 #define ANOMALY_MONITOR_H
 
+#include "anomaly/indexed_priority_queue.h"
+
 #include <android/os/IStatsCompanionService.h>
-#include <indexed_priority_queue.h>
 #include <utils/RefBase.h>
 
-#include <unordered_set>
 #include <queue>
+#include <unordered_set>
 #include <vector>
 
 using namespace android;
@@ -91,8 +92,8 @@
      * Returns and removes all alarms whose timestamp <= the given timestampSec.
      * Always updates the registered alarm if return is non-empty.
      */
-    unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>
-                    popSoonerThan(uint32_t timestampSec);
+    unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> popSoonerThan(
+            uint32_t timestampSec);
 
     /**
      * Returns the projected alarm timestamp that is registered with
@@ -144,4 +145,4 @@
 }  // namespace os
 }  // namespace android
 
-#endif  // ANOMALY_MONITOR_H
\ No newline at end of file
+#endif  // ANOMALY_MONITOR_H
diff --git a/cmds/statsd/src/indexed_priority_queue.h b/cmds/statsd/src/anomaly/indexed_priority_queue.h
similarity index 89%
rename from cmds/statsd/src/indexed_priority_queue.h
rename to cmds/statsd/src/anomaly/indexed_priority_queue.h
index 81e8b3d..1a2e9c2 100644
--- a/cmds/statsd/src/indexed_priority_queue.h
+++ b/cmds/statsd/src/anomaly/indexed_priority_queue.h
@@ -14,15 +14,10 @@
  * limitations under the License.
  */
 
-#ifndef STATSD_INDEXED_PRIORITY_QUEUE_H
-#define STATSD_INDEXED_PRIORITY_QUEUE_H
+#pragma once
 
-// ALOGE can be called from this file. If header loaded by another class, use their LOG_TAG instead.
-#ifndef LOG_TAG
-#define LOG_TAG "statsd(indexed_priority_queue)"
-#endif  // LOG_TAG
+#include "Log.h"
 
-#include <cutils/log.h>
 #include <utils/RefBase.h>
 #include <unordered_map>
 #include <vector>
@@ -132,23 +127,23 @@
 // The same as, but slightly more efficient than, remove(top()).
 template <class AA, class Comparator>
 void indexed_priority_queue<AA, Comparator>::pop() {
-  sp<const AA> a = top();
-  if (a == nullptr) return;
-  const size_t idx = 1;
-  if (idx == size()) {  // if a is the last element
+    sp<const AA> a = top();
+    if (a == nullptr) return;
+    const size_t idx = 1;
+    if (idx == size()) {  // if a is the last element
+        pq.pop_back();
+        indices.erase(a);
+        return;
+    }
+    // move last element (guaranteed not to be at idx) to idx, then delete a
+    sp<const AA> last_a = pq.back();
+    pq[idx] = last_a;
     pq.pop_back();
+    indices[last_a] = idx;
     indices.erase(a);
-    return;
-  }
-  // move last element (guaranteed not to be at idx) to idx, then delete a
-  sp<const AA> last_a = pq.back();
-  pq[idx] = last_a;
-  pq.pop_back();
-  indices[last_a] = idx;
-  indices.erase(a);
 
-  // get the heap back in order (since the element at idx is not in order)
-  sift_down(idx);
+    // get the heap back in order (since the element at idx is not in order)
+    sift_down(idx);
 }
 
 template <class AA, class Comparator>
@@ -227,5 +222,3 @@
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
-
-#endif  // STATSD_INDEXED_PRIORITY_QUEUE_H
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 6188383..c3a06bc 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -13,23 +13,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "CombinationConditionTracker"
+
 #define DEBUG true  // STOPSHIP if true
-#define VLOG(...) \
-    if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
 
 #include "CombinationConditionTracker.h"
-#include <cutils/log.h>
+
 #include <log/logprint.h>
-using std::string;
-using std::unique_ptr;
-using std::unordered_map;
-using std::vector;
 
 namespace android {
 namespace os {
 namespace statsd {
 
+using std::string;
+using std::unique_ptr;
+using std::unordered_map;
+using std::vector;
+
 CombinationConditionTracker::CombinationConditionTracker(const string& name, const int index)
     : ConditionTracker(name, index) {
     VLOG("creating CombinationConditionTracker %s", mName.c_str());
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 2da8fa0..9554e0a 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -14,17 +14,19 @@
  * limitations under the License.
  */
 
-#ifndef CONDITION_TRACKER_H
-#define CONDITION_TRACKER_H
+#pragma once
 
-#include <cutils/log.h>
+#include "Log.h"
+
+#include "condition/condition_util.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/LogMatchingTracker.h"
+#include "matchers/matcher_util.h"
+
 #include <log/logprint.h>
 #include <utils/RefBase.h>
+
 #include <unordered_map>
-#include "../matchers/LogMatchingTracker.h"
-#include "../matchers/matcher_util.h"
-#include "condition_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 namespace android {
 namespace os {
@@ -102,4 +104,3 @@
 }  // namespace os
 }  // namespace android
 
-#endif  // CONDITION_TRACKER_H
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index e78c0de..694908d 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -14,24 +14,22 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "Stats_SimpleConditionTracker"
 #define DEBUG true  // STOPSHIP if true
-#define VLOG(...) \
-    if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
 
 #include "SimpleConditionTracker.h"
-#include <cutils/log.h>
+
 #include <log/logprint.h>
 
+namespace android {
+namespace os {
+namespace statsd {
+
 using std::string;
 using std::unique_ptr;
 using std::unordered_map;
 using std::vector;
 
-namespace android {
-namespace os {
-namespace statsd {
-
 SimpleConditionTracker::SimpleConditionTracker(
         const string& name, const int index, const SimpleCondition& simpleCondition,
         const unordered_map<string, int>& trackerNameIndexMap)
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index cb07d15..c7c8fcc 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
+#include "Log.h"
+
 #include "condition_util.h"
 
-#include <cutils/log.h>
 #include <log/event_tag_map.h>
 #include <log/log_event_list.h>
 #include <log/logprint.h>
@@ -27,14 +28,15 @@
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "stats_util.h"
 
+namespace android {
+namespace os {
+namespace statsd {
+
 using std::set;
 using std::string;
 using std::unordered_map;
 using std::vector;
 
-namespace android {
-namespace os {
-namespace statsd {
 
 ConditionState evaluateCombinationCondition(const std::vector<int>& children,
                                             const LogicalOperation& operation,
diff --git a/cmds/statsd/src/KernelWakelockPuller.h b/cmds/statsd/src/config/ConfigKey.cpp
similarity index 63%
copy from cmds/statsd/src/KernelWakelockPuller.h
copy to cmds/statsd/src/config/ConfigKey.cpp
index 1c16f87..a365dc0 100644
--- a/cmds/statsd/src/KernelWakelockPuller.h
+++ b/cmds/statsd/src/config/ConfigKey.cpp
@@ -14,26 +14,34 @@
  * limitations under the License.
  */
 
-#ifndef STATSD_KERNELWAKELOCKPULLER_H
-#define STATSD_KERNELWAKELOCKPULLER_H
+#include "config/ConfigKey.h"
 
-#include <utils/String16.h>
-#include "StatsPuller.h"
+#include <sstream>
 
 namespace android {
 namespace os {
 namespace statsd {
 
-class KernelWakelockPuller : public StatsPuller {
-public:
-    // a number of stats need to be pulled from StatsCompanionService
-    //
-    const static int PULL_CODE_KERNEL_WAKELOCKS;
-    String16 pull() override;
-};
+using std::ostringstream;
+
+ConfigKey::ConfigKey() {
+}
+
+ConfigKey::ConfigKey(const ConfigKey& that) : mName(that.mName), mUid(that.mUid) {
+}
+
+ConfigKey::ConfigKey(int uid, const string& name) : mName(name), mUid(uid) {
+}
+
+ConfigKey::~ConfigKey() {
+}
+
+string ConfigKey::ToString() const {
+    ostringstream out;
+    out << '(' << mUid << ',' << mName << ')';
+    return out.str();
+}
 
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
-
-#endif  // STATSD_KERNELWAKELOCKPULLER_H
diff --git a/cmds/statsd/src/config/ConfigKey.h b/cmds/statsd/src/config/ConfigKey.h
new file mode 100644
index 0000000..bbf20fd
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigKey.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+#include <functional>
+#include <iostream>
+#include <string>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::hash;
+using std::ostream;
+using std::string;
+
+/**
+ * Uniquely identifies a configuration.
+ */
+class ConfigKey {
+public:
+    ConfigKey();
+    explicit ConfigKey(const ConfigKey& that);
+    ConfigKey(int uid, const string& name);
+    ~ConfigKey();
+
+    inline int GetUid() const {
+        return mUid;
+    }
+    inline const string& GetName() const {
+        return mName;
+    }
+
+    inline bool operator<(const ConfigKey& that) const {
+        if (mUid < that.mUid) {
+            return true;
+        }
+        if (mUid > that.mUid) {
+            return false;
+        }
+        return mName < that.mName;
+    };
+
+    inline bool operator==(const ConfigKey& that) const {
+        return mUid == that.mUid && mName == that.mName;
+    };
+
+    string ToString() const;
+
+private:
+    string mName;
+    int mUid;
+};
+
+inline ostream& operator<<(ostream& os, const ConfigKey& config) {
+    return os << config.ToString();
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+/**
+ * A hash function for ConfigKey so it can be used for unordered_map/set.
+ * Unfortunately this hast to go in std namespace because C++ is fun!
+ */
+namespace std {
+
+using android::os::statsd::ConfigKey;
+
+template <>
+struct hash<ConfigKey> {
+    std::size_t operator()(const ConfigKey& key) const {
+        return (7 * key.GetUid()) ^ ((hash<string>()(key.GetName())));
+    }
+};
+
+}  // namespace std
diff --git a/cmds/statsd/src/KernelWakelockPuller.h b/cmds/statsd/src/config/ConfigListener.cpp
similarity index 65%
copy from cmds/statsd/src/KernelWakelockPuller.h
copy to cmds/statsd/src/config/ConfigListener.cpp
index 1c16f87..21a3f16 100644
--- a/cmds/statsd/src/KernelWakelockPuller.h
+++ b/cmds/statsd/src/config/ConfigListener.cpp
@@ -14,26 +14,18 @@
  * limitations under the License.
  */
 
-#ifndef STATSD_KERNELWAKELOCKPULLER_H
-#define STATSD_KERNELWAKELOCKPULLER_H
-
-#include <utils/String16.h>
-#include "StatsPuller.h"
+#include "config/ConfigListener.h"
 
 namespace android {
 namespace os {
 namespace statsd {
 
-class KernelWakelockPuller : public StatsPuller {
-public:
-    // a number of stats need to be pulled from StatsCompanionService
-    //
-    const static int PULL_CODE_KERNEL_WAKELOCKS;
-    String16 pull() override;
-};
+ConfigListener::ConfigListener() {
+}
+
+ConfigListener::~ConfigListener() {
+}
 
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
-
-#endif  // STATSD_KERNELWAKELOCKPULLER_H
diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h
new file mode 100644
index 0000000..a58766d
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigListener.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include <frameworks/base/cmds/statsd/src/stats_log.pb.h>
+#include "config/ConfigKey.h"
+
+#include <utils/RefBase.h>
+#include <string>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using android::RefBase;
+using std::string;
+
+/**
+ * Callback for different subsystems inside statsd to implement to find out
+ * when a configuration has been added, updated or removed.
+ */
+class ConfigListener : public virtual RefBase {
+public:
+    ConfigListener();
+    virtual ~ConfigListener();
+
+    /**
+     * A configuration was added or updated.
+     */
+    virtual void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) = 0;
+
+    /**
+     * A configuration was removed.
+     */
+    virtual void OnConfigRemoved(const ConfigKey& key) = 0;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
new file mode 100644
index 0000000..2a4d6e2
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2017 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 "config/ConfigManager.h"
+
+#include "stats_util.h"
+
+#include <vector>
+
+#include <stdio.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static StatsdConfig build_fake_config();
+
+ConfigManager::ConfigManager() {
+}
+
+ConfigManager::~ConfigManager() {
+}
+
+void ConfigManager::Startup() {
+    // TODO: Implement me -- read from storage and call onto all of the listeners.
+    // Instead, we'll just make a fake one.
+
+    // this should be called from StatsService when it receives a statsd_config
+    UpdateConfig(ConfigKey(0, "fake"), build_fake_config());
+}
+
+void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
+    mListeners.push_back(listener);
+}
+
+void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& config) {
+    // Add to map
+    mConfigs[key] = config;
+    // Why doesn't this work? mConfigs.insert({key, config});
+
+    // Save to disk
+    update_saved_configs();
+
+    // Tell everyone
+    for (auto& listener : mListeners) {
+        listener->OnConfigUpdated(key, config);
+    }
+}
+
+void ConfigManager::RemoveConfig(const ConfigKey& key) {
+    unordered_map<ConfigKey, StatsdConfig>::iterator it = mConfigs.find(key);
+    if (it != mConfigs.end()) {
+        // Remove from map
+        mConfigs.erase(it);
+
+        // Save to disk
+        update_saved_configs();
+
+        // Tell everyone
+        for (auto& listener : mListeners) {
+            listener->OnConfigRemoved(key);
+        }
+    }
+    // If we didn't find it, just quietly ignore it.
+}
+
+void ConfigManager::RemoveConfigs(int uid) {
+    vector<ConfigKey> removed;
+
+    for (auto it = mConfigs.begin(); it != mConfigs.end();) {
+        // Remove from map
+        if (it->first.GetUid() == uid) {
+            removed.push_back(it->first);
+            it = mConfigs.erase(it);
+        } else {
+            it++;
+        }
+    }
+
+    // Remove separately so if they do anything in the callback they can't mess up our iteration.
+    for (auto& key : removed) {
+        // Tell everyone
+        for (auto& listener : mListeners) {
+            listener->OnConfigRemoved(key);
+        }
+    }
+}
+
+void ConfigManager::Dump(FILE* out) {
+    fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size());
+    fprintf(out, "     uid name\n");
+    for (unordered_map<ConfigKey, StatsdConfig>::const_iterator it = mConfigs.begin();
+         it != mConfigs.end(); it++) {
+        fprintf(out, "  %6d %s\n", it->first.GetUid(), it->first.GetName().c_str());
+        // TODO: Print the contents of the config too.
+    }
+}
+
+void ConfigManager::update_saved_configs() {
+    // TODO: Implement me -- write to disk.
+}
+
+static StatsdConfig build_fake_config() {
+    // HACK: Hard code a test metric for counting screen on events...
+    StatsdConfig config;
+    config.set_config_id(12345L);
+
+    // One count metric to count screen on
+    CountMetric* metric = config.add_count_metric();
+    metric->set_metric_id(20150717L);
+    metric->set_what("SCREEN_IS_ON");
+    metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+
+    // One count metric to count PHOTO_CHANGE_OR_CHROME_CRASH
+    metric = config.add_count_metric();
+    metric->set_metric_id(20150718L);
+    metric->set_what("PHOTO_PROCESS_STATE_CHANGE");
+    metric->mutable_bucket()->set_bucket_size_millis(60 * 1000L);
+    metric->set_condition("SCREEN_IS_ON");
+
+    LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+    eventMatcher->set_name("SCREEN_IS_ON");
+
+    SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+    simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+    simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+            2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+    eventMatcher = config.add_log_entry_matcher();
+    eventMatcher->set_name("SCREEN_IS_OFF");
+
+    simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
+    simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
+            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+    simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
+            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
+
+    LogEntryMatcher* procEventMatcher = config.add_log_entry_matcher();
+    procEventMatcher->set_name("PHOTO_CRASH");
+
+    SimpleLogEntryMatcher* simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
+    KeyValueMatcher* keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(1002 /*pkg*/);
+    keyValueMatcher->set_eq_string(
+            "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
+    keyValueMatcher->set_eq_int(2);
+
+    procEventMatcher = config.add_log_entry_matcher();
+    procEventMatcher->set_name("PHOTO_START");
+
+    simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
+    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(1002 /*pkg*/);
+    keyValueMatcher->set_eq_string(
+            "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(1 /*STATE*/);
+    keyValueMatcher->set_eq_int(1);
+
+    procEventMatcher = config.add_log_entry_matcher();
+    procEventMatcher->set_name("PHOTO_PROCESS_STATE_CHANGE");
+    LogEntryMatcher_Combination* combinationMatcher = procEventMatcher->mutable_combination();
+    combinationMatcher->set_operation(LogicalOperation::OR);
+    combinationMatcher->add_matcher("PHOTO_START");
+    combinationMatcher->add_matcher("PHOTO_CRASH");
+
+    procEventMatcher = config.add_log_entry_matcher();
+    procEventMatcher->set_name("CHROME_CRASH");
+
+    simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
+    simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
+    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(1002 /*pkg*/);
+    keyValueMatcher->set_eq_string(
+            "com.android.chrome" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
+
+    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
+    keyValueMatcher->mutable_key_matcher()->set_key(1 /*STATE*/);
+    keyValueMatcher->set_eq_int(2);
+
+    procEventMatcher = config.add_log_entry_matcher();
+    procEventMatcher->set_name("PHOTO_CHANGE_OR_CHROME_CRASH");
+    combinationMatcher = procEventMatcher->mutable_combination();
+    combinationMatcher->set_operation(LogicalOperation::OR);
+    combinationMatcher->add_matcher("PHOTO_PROCESS_STATE_CHANGE");
+    combinationMatcher->add_matcher("CHROME_CRASH");
+
+    Condition* condition = config.add_condition();
+    condition->set_name("SCREEN_IS_ON");
+    SimpleCondition* simpleCondition = condition->mutable_simple_condition();
+    simpleCondition->set_start("SCREEN_IS_ON");
+    simpleCondition->set_stop("SCREEN_IS_OFF");
+
+    condition = config.add_condition();
+    condition->set_name("PHOTO_STARTED");
+
+    simpleCondition = condition->mutable_simple_condition();
+    simpleCondition->set_start("PHOTO_START");
+    simpleCondition->set_stop("PHOTO_CRASH");
+
+    condition = config.add_condition();
+    condition->set_name("SCREEN_IS_OFF");
+
+    simpleCondition = condition->mutable_simple_condition();
+    simpleCondition->set_start("SCREEN_IS_OFF");
+    simpleCondition->set_stop("SCREEN_IS_ON");
+
+    condition = config.add_condition();
+    condition->set_name("SCREEN_IS_EITHER_ON_OFF");
+
+    Condition_Combination* combination = condition->mutable_combination();
+    combination->set_operation(LogicalOperation::OR);
+    combination->add_condition("SCREEN_IS_ON");
+    combination->add_condition("SCREEN_IS_OFF");
+
+    condition = config.add_condition();
+    condition->set_name("SCREEN_IS_NEITHER_ON_OFF");
+
+    combination = condition->mutable_combination();
+    combination->set_operation(LogicalOperation::NOR);
+    combination->add_condition("SCREEN_IS_ON");
+    combination->add_condition("SCREEN_IS_OFF");
+
+    return config;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
new file mode 100644
index 0000000..5d73eaf
--- /dev/null
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include "config/ConfigKey.h"
+#include "config/ConfigListener.h"
+
+#include <string>
+#include <unordered_map>
+
+#include <stdio.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using android::RefBase;
+using std::string;
+using std::unordered_map;
+using std::vector;
+
+/**
+ * Keeps track of which configurations have been set from various sources.
+ *
+ * TODO: Store the configs persistently too.
+ * TODO: Dump method for debugging.
+ */
+class ConfigManager : public virtual RefBase {
+public:
+    ConfigManager();
+    virtual ~ConfigManager();
+
+    /**
+     * Call to load the saved configs from disk.
+     *
+     * TODO: Implement me
+     */
+    void Startup();
+
+    /**
+     * Someone else wants to know about the configs.
+     */
+    void AddListener(const sp<ConfigListener>& listener);
+
+    /**
+     * A configuration was added or updated.
+     *
+     * Reports this to listeners.
+     */
+    void UpdateConfig(const ConfigKey& key, const StatsdConfig& data);
+
+    /**
+     * A configuration was removed.
+     *
+     * Reports this to listeners.
+     */
+    void RemoveConfig(const ConfigKey& key);
+
+    /**
+     * Remove all of the configs for the given uid.
+     */
+    void RemoveConfigs(int uid);
+
+    /**
+     * Text dump of our state for debugging.
+     */
+    void Dump(FILE* out);
+
+private:
+    /**
+     * Save the configs to disk.
+     */
+    void update_saved_configs();
+
+    /**
+     * The Configs that have been set
+     */
+    unordered_map<ConfigKey, StatsdConfig> mConfigs;
+
+    /**
+     * The ConfigListeners that will be told about changes.
+     */
+    vector<sp<ConfigListener>> mListeners;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/KernelWakelockPuller.cpp b/cmds/statsd/src/external/KernelWakelockPuller.cpp
similarity index 73%
rename from cmds/statsd/src/KernelWakelockPuller.cpp
rename to cmds/statsd/src/external/KernelWakelockPuller.cpp
index 1798f9d..b9abee0 100644
--- a/cmds/statsd/src/KernelWakelockPuller.cpp
+++ b/cmds/statsd/src/external/KernelWakelockPuller.cpp
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-#include "KernelWakelockPuller.h"
+#include "Log.h"
+
 #include <android/os/IStatsCompanionService.h>
 #include <binder/IPCThreadState.h>
-#include <cutils/log.h>
 #include <private/android_filesystem_config.h>
-#include "StatsPuller.h"
 #include "StatsService.h"
+#include "external/KernelWakelockPuller.h"
+#include "external/StatsPuller.h"
 
 using namespace android;
 using namespace android::base;
@@ -40,15 +41,15 @@
     sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService();
     String16 returned_value("");
     if (statsCompanion != NULL) {
-      Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS,
-                                             &returned_value);
-      if (!status.isOk()) {
-          ALOGW("error pulling kernel wakelock");
-      }
-      ALOGD("KernelWakelockPuller::pull succeeded!");
-      // TODO: remove this when we integrate into aggregation chain.
-      ALOGD("%s", String8(returned_value).string());
-      return returned_value;
+        Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS,
+                                                 &returned_value);
+        if (!status.isOk()) {
+            ALOGW("error pulling kernel wakelock");
+        }
+        ALOGD("KernelWakelockPuller::pull succeeded!");
+        // TODO: remove this when we integrate into aggregation chain.
+        ALOGD("%s", String8(returned_value).string());
+        return returned_value;
     } else {
         ALOGW("statsCompanion not found!");
         return String16();
diff --git a/cmds/statsd/src/KernelWakelockPuller.h b/cmds/statsd/src/external/KernelWakelockPuller.h
similarity index 96%
rename from cmds/statsd/src/KernelWakelockPuller.h
rename to cmds/statsd/src/external/KernelWakelockPuller.h
index 1c16f87..1ec3376 100644
--- a/cmds/statsd/src/KernelWakelockPuller.h
+++ b/cmds/statsd/src/external/KernelWakelockPuller.h
@@ -18,7 +18,7 @@
 #define STATSD_KERNELWAKELOCKPULLER_H
 
 #include <utils/String16.h>
-#include "StatsPuller.h"
+#include "external/StatsPuller.h"
 
 namespace android {
 namespace os {
diff --git a/cmds/statsd/src/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
similarity index 100%
rename from cmds/statsd/src/StatsPuller.h
rename to cmds/statsd/src/external/StatsPuller.h
diff --git a/cmds/statsd/src/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
similarity index 93%
rename from cmds/statsd/src/StatsPullerManager.cpp
rename to cmds/statsd/src/external/StatsPullerManager.cpp
index f4cf1ce..6e8d58bc 100644
--- a/cmds/statsd/src/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -14,15 +14,13 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "StatsPullerManager"
 #define DEBUG true
+#include "Log.h"
 
-#include "StatsPullerManager.h"
 #include <android/os/IStatsCompanionService.h>
-#include <cutils/log.h>
-#include "StatsService.h"
 #include "KernelWakelockPuller.h"
-
+#include "StatsService.h"
+#include "external/StatsPullerManager.h"
 
 using namespace android;
 
diff --git a/cmds/statsd/src/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
similarity index 97%
rename from cmds/statsd/src/StatsPullerManager.h
rename to cmds/statsd/src/external/StatsPullerManager.h
index ab36df5..f143424 100644
--- a/cmds/statsd/src/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -19,7 +19,7 @@
 
 #include <utils/String16.h>
 #include <unordered_map>
-#include "StatsPuller.h"
+#include "external/StatsPuller.h"
 
 namespace android {
 namespace os {
@@ -41,7 +41,6 @@
     std::unordered_map<int, std::unique_ptr<StatsPuller>> mStatsPullers;
 };
 
-
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/KernelWakelockPuller.h b/cmds/statsd/src/logd/LogListener.cpp
similarity index 65%
copy from cmds/statsd/src/KernelWakelockPuller.h
copy to cmds/statsd/src/logd/LogListener.cpp
index 1c16f87..6ac7978 100644
--- a/cmds/statsd/src/KernelWakelockPuller.h
+++ b/cmds/statsd/src/logd/LogListener.cpp
@@ -14,26 +14,28 @@
  * limitations under the License.
  */
 
-#ifndef STATSD_KERNELWAKELOCKPULLER_H
-#define STATSD_KERNELWAKELOCKPULLER_H
+#include "logd/LogReader.h"
 
-#include <utils/String16.h>
-#include "StatsPuller.h"
+#include <log/log_read.h>
+
+#include <utils/Errors.h>
+
+#include <time.h>
+#include <unistd.h>
+
+using namespace android;
+using namespace std;
 
 namespace android {
 namespace os {
 namespace statsd {
 
-class KernelWakelockPuller : public StatsPuller {
-public:
-    // a number of stats need to be pulled from StatsCompanionService
-    //
-    const static int PULL_CODE_KERNEL_WAKELOCKS;
-    String16 pull() override;
-};
+LogListener::LogListener() {
+}
+
+LogListener::~LogListener() {
+}
 
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
-
-#endif  // STATSD_KERNELWAKELOCKPULLER_H
diff --git a/cmds/statsd/src/KernelWakelockPuller.h b/cmds/statsd/src/logd/LogListener.h
similarity index 63%
copy from cmds/statsd/src/KernelWakelockPuller.h
copy to cmds/statsd/src/logd/LogListener.h
index 1c16f87..786a793 100644
--- a/cmds/statsd/src/KernelWakelockPuller.h
+++ b/cmds/statsd/src/logd/LogListener.h
@@ -14,26 +14,29 @@
  * limitations under the License.
  */
 
-#ifndef STATSD_KERNELWAKELOCKPULLER_H
-#define STATSD_KERNELWAKELOCKPULLER_H
+#pragma once
 
-#include <utils/String16.h>
-#include "StatsPuller.h"
+#include <log/log_read.h>
+#include <utils/RefBase.h>
+#include <vector>
 
 namespace android {
 namespace os {
 namespace statsd {
 
-class KernelWakelockPuller : public StatsPuller {
+/**
+ * Callback for LogReader
+ */
+class LogListener : public virtual android::RefBase {
 public:
-    // a number of stats need to be pulled from StatsCompanionService
-    //
-    const static int PULL_CODE_KERNEL_WAKELOCKS;
-    String16 pull() override;
+    LogListener();
+    virtual ~LogListener();
+
+    // TODO: Rather than using log_msg, which doesn't have any real internal structure
+    // here, we should pull this out into our own LogEntry class.
+    virtual void OnLogEvent(const log_msg& msg) = 0;
 };
 
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
-
-#endif  // STATSD_KERNELWAKELOCKPULLER_H
diff --git a/cmds/statsd/src/LogReader.cpp b/cmds/statsd/src/logd/LogReader.cpp
similarity index 84%
rename from cmds/statsd/src/LogReader.cpp
rename to cmds/statsd/src/logd/LogReader.cpp
index c4ac337..23d3698a 100644
--- a/cmds/statsd/src/LogReader.cpp
+++ b/cmds/statsd/src/logd/LogReader.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "LogReader.h"
+#include "logd/LogReader.h"
 
 #include <log/log_read.h>
 
@@ -33,24 +33,12 @@
 #define SNOOZE_INITIAL_MS 100
 #define SNOOZE_MAX_MS (10 * 60 * 1000)  // Ten minutes
 
-// ================================================================================
-LogListener::LogListener() {
-}
-
-LogListener::~LogListener() {
-}
-
-// ================================================================================
-LogReader::LogReader() {
+LogReader::LogReader(const sp<LogListener>& listener) : mListener(listener) {
 }
 
 LogReader::~LogReader() {
 }
 
-void LogReader::AddListener(const sp<LogListener>& listener) {
-    m_listeners.push_back(listener);
-}
-
 void LogReader::Run() {
     int nextSnoozeMs = SNOOZE_INITIAL_MS;
 
@@ -119,11 +107,8 @@
             // Record that we read one (used above to know how to snooze).
             lineCount++;
 
-            // Call the listeners
-            for (vector<sp<LogListener> >::iterator it = m_listeners.begin();
-                 it != m_listeners.end(); it++) {
-                (*it)->OnLogEvent(msg);
-            }
+            // Call the listener
+            mListener->OnLogEvent(msg);
         }
     }
 
diff --git a/cmds/statsd/src/LogReader.h b/cmds/statsd/src/logd/LogReader.h
similarity index 67%
rename from cmds/statsd/src/LogReader.h
rename to cmds/statsd/src/logd/LogReader.h
index fc19585..6ca0646 100644
--- a/cmds/statsd/src/LogReader.h
+++ b/cmds/statsd/src/logd/LogReader.h
@@ -17,6 +17,8 @@
 #ifndef LOGREADER_H
 #define LOGREADER_H
 
+#include "logd/LogListener.h"
+
 #include <log/log_read.h>
 #include <utils/RefBase.h>
 
@@ -27,27 +29,14 @@
 namespace statsd {
 
 /**
- * Callback for LogReader
- */
-class LogListener : public virtual android::RefBase {
-public:
-    LogListener();
-    virtual ~LogListener();
-
-    // TODO: Rather than using log_msg, which doesn't have any real internal structure
-    // here, we should pull this out into our own LogEntry class.
-    virtual void OnLogEvent(const log_msg& msg) = 0;
-};
-
-/**
  * Class to read logs from logd.
  */
 class LogReader : public virtual android::RefBase {
 public:
     /**
-     * Construct the LogReader with a pointer back to the StatsService
+     * Construct the LogReader with the event listener. (Which is StatsService)
      */
-    LogReader();
+    LogReader(const sp<LogListener>& listener);
 
     /**
      * Destructor.
@@ -55,20 +44,15 @@
     virtual ~LogReader();
 
     /**
-     * Add a LogListener class.
-     */
-    void AddListener(const android::sp<LogListener>& listener);
-
-    /**
      * Run the main LogReader loop
      */
     void Run();
 
 private:
     /**
-     * List of listeners to call back on when we do get an event.
+     * Who is going to get the events when they're read.
      */
-    std::vector<android::sp<LogListener> > m_listeners;
+    sp<LogListener> mListener;
 
     /**
      * Connect to a single instance of logd, and read until there's a read error.
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 37477dc..a740280 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -14,20 +14,16 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "statsd"
+#include "Log.h"
 
-#include "LogEntryPrinter.h"
-#include "LogReader.h"
-#include "StatsLogProcessor.h"
 #include "StatsService.h"
-#include "UidMap.h"
+#include "logd/LogReader.h"
 
 #include <binder/IInterface.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <binder/Status.h>
-#include <cutils/log.h>
 #include <utils/Looper.h>
 #include <utils/StrongPointer.h>
 
@@ -53,16 +49,12 @@
 static void* log_reader_thread_func(void* cookie) {
     log_reader_thread_data* data = static_cast<log_reader_thread_data*>(cookie);
 
-    sp<LogReader> reader = new LogReader();
+    sp<LogReader> reader = new LogReader(data->service);
 
-    // Put the printer one first, so it will print before the real ones.
-    reader->AddListener(new LogEntryPrinter(STDOUT_FILENO));
-    sp<StatsLogProcessor> main_processor = new StatsLogProcessor(data->service->getUidMap());
-    data->service->setProcessor(main_processor);
-    reader->AddListener(main_processor);
+    // Tell StatsService that we're ready to go.
+    data->service->Startup();
 
-    // TODO: Construct and add real LogListners here.
-
+    // Run the read loop. Never returns.
     reader->Run();
 
     ALOGW("statsd LogReader.Run() is not supposed to return.");
@@ -127,6 +119,8 @@
 
     // TODO: This line is temporary, since statsd doesn't start up automatically (and therefore
     // the call in StatsService::SystemRunning() won't ever be called right now).
+    // TODO: Are you sure? Don't we need to reconnect to the system process if we get restarted?
+    //  --joeo
     service->sayHiToStatsCompanion();
 
     // Start the log reader thread
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
index 9f9b648..f1e0d5a 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
@@ -14,20 +14,21 @@
  * limitations under the License.
  */
 
-#include "CombinationLogMatchingTracker.h"
+#include "Log.h"
 
-#include <cutils/log.h>
-#include "matcher_util.h"
+#include "CombinationLogMatchingTracker.h"
+#include "matchers/matcher_util.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
 using std::set;
 using std::string;
 using std::unique_ptr;
 using std::unordered_map;
 using std::vector;
 
-namespace android {
-namespace os {
-namespace statsd {
-
 CombinationLogMatchingTracker::CombinationLogMatchingTracker(const string& name, const int index)
     : LogMatchingTracker(name, index) {
 }
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
index 1c83039..815baf7 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
@@ -14,23 +14,22 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "SimpleLogMatchingTracker"
 #define DEBUG true  // STOPSHIP if true
-#define VLOG(...) \
-    if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
 
 #include "SimpleLogMatchingTracker.h"
-#include <cutils/log.h>
+
 #include <log/logprint.h>
 
+namespace android {
+namespace os {
+namespace statsd {
+
 using std::string;
 using std::unique_ptr;
 using std::unordered_map;
 using std::vector;
 
-namespace android {
-namespace os {
-namespace statsd {
 
 SimpleLogMatchingTracker::SimpleLogMatchingTracker(const string& name, const int index,
                                                    const SimpleLogEntryMatcher& matcher)
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 3308f3a..ce0576c 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -14,19 +14,21 @@
  * limitations under the License.
  */
 
-#include "matcher_util.h"
-#include <cutils/log.h>
+#include "Log.h"
+
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/LogMatchingTracker.h"
+#include "matchers/matcher_util.h"
+#include "stats_util.h"
+
 #include <log/event_tag_map.h>
 #include <log/log_event_list.h>
 #include <log/logprint.h>
 #include <utils/Errors.h>
-#include <unordered_map>
-#include "LogMatchingTracker.h"
-#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
-#include "stats_util.h"
 
 #include <sstream>
+#include <unordered_map>
 
 using std::set;
 using std::string;
diff --git a/cmds/statsd/src/metrics/CountAnomalyTracker.cpp b/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
index ebd53e0..e1c2b8b 100644
--- a/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
+++ b/cmds/statsd/src/metrics/CountAnomalyTracker.cpp
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "CountAnomaly"
 #define DEBUG true  // STOPSHIP if true
+#include "Log.h"
+
 #define VLOG(...) \
     if (DEBUG) ALOGD(__VA_ARGS__);
 
 #include "CountAnomalyTracker.h"
 
-#include <cutils/log.h>
-
 namespace android {
 namespace os {
 namespace statsd {
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index e98999e..68d0a30 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -14,10 +14,8 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "CountMetric"
 #define DEBUG true  // STOPSHIP if true
-#define VLOG(...) \
-    if (DEBUG) ALOGD(__VA_ARGS__);
+#include "Log.h"
 
 #include "CountMetricProducer.h"
 #include "CountAnomalyTracker.h"
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 6c39d98..7bc7f97 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -17,10 +17,11 @@
 #ifndef METRIC_PRODUCER_H
 #define METRIC_PRODUCER_H
 
+#include "matchers/matcher_util.h"
+#include "packages/PackageInfoListener.h"
+
 #include <log/logprint.h>
 #include <utils/RefBase.h>
-#include "../matchers/matcher_util.h"
-#include "PackageInfoListener.h"
 
 namespace android {
 namespace os {
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 1e65f58..b77daf1 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -13,13 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define LOG_TAG "MetricManager"
 #define DEBUG true  // STOPSHIP if true
+#include "Log.h"
 #define VLOG(...) \
     if (DEBUG) ALOGD(__VA_ARGS__);
 
 #include "MetricsManager.h"
-#include <cutils/log.h>
 #include <log/logprint.h>
 #include "../condition/CombinationConditionTracker.h"
 #include "../condition/SimpleConditionTracker.h"
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 70c34db..2f3fad9 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -14,16 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef METRICS_MANAGER_H
-#define METRICS_MANAGER_H
+#pragma once
 
-#include <cutils/log.h>
+#include "condition/ConditionTracker.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/LogMatchingTracker.h"
+#include "metrics/MetricProducer.h"
+
 #include <log/logprint.h>
 #include <unordered_map>
-#include "../condition/ConditionTracker.h"
-#include "../matchers/LogMatchingTracker.h"
-#include "MetricProducer.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 namespace android {
 namespace os {
@@ -94,4 +93,3 @@
 }  // namespace os
 }  // namespace android
 
-#endif  // METRICS_MANAGER_H
diff --git a/cmds/statsd/src/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
similarity index 96%
rename from cmds/statsd/src/PackageInfoListener.h
rename to cmds/statsd/src/packages/PackageInfoListener.h
index 476c1d9..8b948de 100644
--- a/cmds/statsd/src/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -35,4 +35,4 @@
 }  // namespace os
 }  // namespace android
 
-#endif //STATSD_PACKAGE_INFO_LISTENER_H
+#endif  // STATSD_PACKAGE_INFO_LISTENER_H
diff --git a/cmds/statsd/src/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
similarity index 79%
rename from cmds/statsd/src/UidMap.cpp
rename to cmds/statsd/src/packages/UidMap.cpp
index 76a7f3f..f4621ee 100644
--- a/cmds/statsd/src/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-#include "UidMap.h"
-#include <cutils/log.h>
+#include "Log.h"
+
+#include "packages/UidMap.h"
+
 #include <utils/Errors.h>
 
 using namespace android;
@@ -48,18 +50,18 @@
     return 0;
 }
 
-void UidMap::updateMap(const vector <int32_t> &uid, const vector <int32_t> &versionCode,
-                       const vector <String16> &packageName) {
-    lock_guard<mutex> lock(mMutex); // Exclusively lock for updates.
+void UidMap::updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
+                       const vector<String16>& packageName) {
+    lock_guard<mutex> lock(mMutex);  // Exclusively lock for updates.
 
     mMap.clear();
-    for (unsigned long j=0; j<uid.size(); j++) {
-        mMap.insert(make_pair(uid[j], AppData(string(String8(packageName[j]).string()),
-                                              versionCode[j])));
+    for (unsigned long j = 0; j < uid.size(); j++) {
+        mMap.insert(make_pair(uid[j],
+                              AppData(string(String8(packageName[j]).string()), versionCode[j])));
     }
 
-    if (mOutput.initial_size() == 0) { // Provide the initial states in the mOutput proto
-        for (unsigned long j=0; j<uid.size(); j++) {
+    if (mOutput.initial_size() == 0) {  // Provide the initial states in the mOutput proto
+        for (unsigned long j = 0; j < uid.size(); j++) {
             auto t = mOutput.add_initial();
             t->set_app(string(String8(packageName[j]).string()));
             t->set_version(int(versionCode[j]));
@@ -68,7 +70,7 @@
     }
 }
 
-void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode){
+void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode) {
     lock_guard<mutex> lock(mMutex);
 
     string app = string(String8(app_16).string());
@@ -80,7 +82,7 @@
 
     auto log = mOutput.add_changes();
     log->set_deletion(false);
-    //log.timestamp = TODO: choose how timestamps are computed
+    // log.timestamp = TODO: choose how timestamps are computed
     log->set_app(app);
     log->set_uid(uid);
     log->set_version(versionCode);
@@ -99,15 +101,14 @@
     mMap.insert(make_pair(uid, AppData(app, int(versionCode))));
 }
 
-
-void UidMap::removeApp(const String16& app_16, const int32_t& uid){
+void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
     lock_guard<mutex> lock(mMutex);
 
     string app = string(String8(app_16).string());
 
     auto log = mOutput.add_changes();
     log->set_deletion(true);
-    //log.timestamp = TODO: choose how timestamps are computed
+    // log.timestamp = TODO: choose how timestamps are computed
     log->set_app(app);
     log->set_uid(uid);
 
@@ -123,19 +124,19 @@
 }
 
 void UidMap::addListener(sp<PackageInfoListener> producer) {
-    lock_guard<mutex> lock(mMutex); // Lock for updates
+    lock_guard<mutex> lock(mMutex);  // Lock for updates
     mSubscribers.insert(producer);
 }
 
 void UidMap::removeListener(sp<PackageInfoListener> producer) {
-    lock_guard<mutex> lock(mMutex); // Lock for updates
+    lock_guard<mutex> lock(mMutex);  // Lock for updates
     mSubscribers.erase(producer);
 }
 
 UidMapping UidMap::getAndClearOutput() {
-    lock_guard<mutex> lock(mMutex); // Lock for updates
+    lock_guard<mutex> lock(mMutex);  // Lock for updates
 
-    auto ret = UidMapping(mOutput); // Copy that will be returned.
+    auto ret = UidMapping(mOutput);  // Copy that will be returned.
     mOutput.Clear();
 
     // Re-initialize the initial state for the outputs. This results in extra data being uploaded
@@ -154,11 +155,11 @@
     lock_guard<mutex> lock(mMutex);
 
     for (auto it : mMap) {
-        fprintf(out, "%s, v%d (%i)\n", it.second.packageName.c_str(), it.second.versionCode, it.first);
+        fprintf(out, "%s, v%d (%i)\n", it.second.packageName.c_str(), it.second.versionCode,
+                it.first);
     }
 }
 
-
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/UidMap.h b/cmds/statsd/src/packages/UidMap.h
similarity index 95%
rename from cmds/statsd/src/UidMap.h
rename to cmds/statsd/src/packages/UidMap.h
index 1481010..d550372 100644
--- a/cmds/statsd/src/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -18,17 +18,17 @@
 #define STATSD_UIDMAP_H
 
 #include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
-#include "PackageInfoListener.h"
+#include "packages/PackageInfoListener.h"
 
 #include <binder/IResultReceiver.h>
 #include <binder/IShellCallback.h>
 #include <log/logprint.h>
-#include <mutex>
-#include <string>
 #include <stdio.h>
-#include <set>
-#include <unordered_map>
 #include <utils/RefBase.h>
+#include <mutex>
+#include <set>
+#include <string>
+#include <unordered_map>
 
 using namespace std;
 
@@ -40,12 +40,12 @@
     const string packageName;
     int versionCode;
 
-    AppData(const string& a, const int v) : packageName(a), versionCode(v) {};
+    AppData(const string& a, const int v) : packageName(a), versionCode(v){};
 };
 
 // UidMap keeps track of what the corresponding app name (APK name) and version code for every uid
 // at any given moment. This map must be updated by StatsCompanionService.
-class UidMap : public virtual android::RefBase  {
+class UidMap : public virtual android::RefBase {
 public:
     /*
      * All three inputs must be the same size, and the jth element in each array refers to the same
@@ -93,5 +93,4 @@
 }  // namespace os
 }  // namespace android
 
-#endif //STATSD_UIDMAP_H
-
+#endif  // STATSD_UIDMAP_H
diff --git a/cmds/statsd/src/stats_util.cpp b/cmds/statsd/src/stats_util.cpp
index 978b228..5157adf 100644
--- a/cmds/statsd/src/stats_util.cpp
+++ b/cmds/statsd/src/stats_util.cpp
@@ -128,162 +128,6 @@
     return eventMetricData;
 }
 
-StatsdConfig buildFakeConfig() {
-    // HACK: Hard code a test metric for counting screen on events...
-    StatsdConfig config;
-    config.set_config_id(12345L);
-
-    // One count metric to count screen on
-    CountMetric* metric = config.add_count_metric();
-    metric->set_metric_id(20150717L);
-    metric->set_what("SCREEN_IS_ON");
-    metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
-
-    // One count metric to count PHOTO_CHANGE_OR_CHROME_CRASH
-    metric = config.add_count_metric();
-    metric->set_metric_id(20150718L);
-    metric->set_what("PHOTO_PROCESS_STATE_CHANGE");
-    metric->mutable_bucket()->set_bucket_size_millis(60 * 1000L);
-    metric->set_condition("SCREEN_IS_ON");
-
-
-    LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
-    eventMatcher->set_name("SCREEN_IS_ON");
-
-    SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
-    simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
-            2 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-
-
-    eventMatcher = config.add_log_entry_matcher();
-    eventMatcher->set_name("SCREEN_IS_OFF");
-
-    simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogEntryMatcher->add_tag(2 /*SCREEN_STATE_CHANGE*/);
-    simpleLogEntryMatcher->add_key_value_matcher()->mutable_key_matcher()->set_key(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    simpleLogEntryMatcher->mutable_key_value_matcher(0)->set_eq_int(
-            1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
-
-
-
-    LogEntryMatcher* procEventMatcher = config.add_log_entry_matcher();
-    procEventMatcher->set_name("PHOTO_CRASH");
-
-    SimpleLogEntryMatcher* simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
-    KeyValueMatcher* keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                1002 /*pkg*/);
-    keyValueMatcher->set_eq_string(
-            "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                                   1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE*/);
-    keyValueMatcher->set_eq_int(2);
-
-
-    procEventMatcher = config.add_log_entry_matcher();
-    procEventMatcher->set_name("PHOTO_START");
-
-    simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
-    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                1002 /*pkg*/);
-    keyValueMatcher->set_eq_string(
-            "com.google.android.apps.photos" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                                   1 /*STATE*/);
-    keyValueMatcher->set_eq_int(1);
-
-
-    procEventMatcher = config.add_log_entry_matcher();
-    procEventMatcher->set_name("PHOTO_PROCESS_STATE_CHANGE");
-    LogEntryMatcher_Combination* combinationMatcher = procEventMatcher->mutable_combination();
-    combinationMatcher->set_operation(LogicalOperation::OR);
-    combinationMatcher->add_matcher("PHOTO_START");
-    combinationMatcher->add_matcher("PHOTO_CRASH");
-
-
-    procEventMatcher = config.add_log_entry_matcher();
-    procEventMatcher->set_name("CHROME_CRASH");
-
-    simpleLogMatcher2 = procEventMatcher->mutable_simple_log_entry_matcher();
-    simpleLogMatcher2->add_tag(1112 /*PROCESS_STATE_CHANGE*/);
-    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                1002 /*pkg*/);
-    keyValueMatcher->set_eq_string(
-            "com.android.chrome" /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_ON*/);
-
-    keyValueMatcher = simpleLogMatcher2->add_key_value_matcher();
-    keyValueMatcher->mutable_key_matcher()->set_key(
-                                   1 /*STATE*/);
-    keyValueMatcher->set_eq_int(2);
-
-
-
-    procEventMatcher = config.add_log_entry_matcher();
-    procEventMatcher->set_name("PHOTO_CHANGE_OR_CHROME_CRASH");
-    combinationMatcher = procEventMatcher->mutable_combination();
-    combinationMatcher->set_operation(LogicalOperation::OR);
-    combinationMatcher->add_matcher("PHOTO_PROCESS_STATE_CHANGE");
-    combinationMatcher->add_matcher("CHROME_CRASH");
-
-
-
-    Condition* condition = config.add_condition();
-    condition->set_name("SCREEN_IS_ON");
-    SimpleCondition* simpleCondition = condition->mutable_simple_condition();
-    simpleCondition->set_start("SCREEN_IS_ON");
-    simpleCondition->set_stop("SCREEN_IS_OFF");
-
-
-    condition = config.add_condition();
-        condition->set_name("PHOTO_STARTED");
-
-        simpleCondition = condition->mutable_simple_condition();
-        simpleCondition->set_start("PHOTO_START");
-        simpleCondition->set_stop("PHOTO_CRASH");
-
-
-    condition = config.add_condition();
-    condition->set_name("SCREEN_IS_OFF");
-
-    simpleCondition = condition->mutable_simple_condition();
-    simpleCondition->set_start("SCREEN_IS_OFF");
-    simpleCondition->set_stop("SCREEN_IS_ON");
-
-
-    condition = config.add_condition();
-    condition->set_name("SCREEN_IS_EITHER_ON_OFF");
-
-    Condition_Combination* combination = condition->mutable_combination();
-    combination->set_operation(LogicalOperation::OR);
-    combination->add_condition("SCREEN_IS_ON");
-    combination->add_condition("SCREEN_IS_OFF");
-
-
-    condition = config.add_condition();
-    condition->set_name("SCREEN_IS_NEITHER_ON_OFF");
-
-    combination = condition->mutable_combination();
-    combination->set_operation(LogicalOperation::NOR);
-    combination->add_condition("SCREEN_IS_ON");
-    combination->add_condition("SCREEN_IS_OFF");
-
-    return config;
-}
-
-
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index 25b9bba..38174bf 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -16,8 +16,8 @@
 #ifndef PARSE_UTIL_H
 #define PARSE_UTIL_H
 
-#include "DropboxWriter.h"
-#include "LogReader.h"
+#include "logd/LogReader.h"
+#include "storage/DropboxWriter.h"
 
 #include <log/logprint.h>
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
@@ -30,8 +30,6 @@
 
 int getTagId(log_msg msg);
 
-StatsdConfig buildFakeConfig();
-
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/DropboxReader.cpp b/cmds/statsd/src/storage/DropboxReader.cpp
similarity index 98%
rename from cmds/statsd/src/DropboxReader.cpp
rename to cmds/statsd/src/storage/DropboxReader.cpp
index 430e7af..c561959 100644
--- a/cmds/statsd/src/DropboxReader.cpp
+++ b/cmds/statsd/src/storage/DropboxReader.cpp
@@ -17,14 +17,14 @@
 #include <android/os/DropBoxManager.h>
 #include <androidfw/ZipUtils.h>
 
-#include "DropboxReader.h"
+#include "storage/DropboxReader.h"
 
-using android::String16;
-using android::ZipUtils;
 using android::base::unique_fd;
 using android::binder::Status;
 using android::os::DropBoxManager;
 using android::sp;
+using android::String16;
+using android::ZipUtils;
 using std::vector;
 
 namespace android {
diff --git a/cmds/statsd/src/DropboxReader.h b/cmds/statsd/src/storage/DropboxReader.h
similarity index 100%
rename from cmds/statsd/src/DropboxReader.h
rename to cmds/statsd/src/storage/DropboxReader.h
diff --git a/cmds/statsd/src/DropboxWriter.cpp b/cmds/statsd/src/storage/DropboxWriter.cpp
similarity index 97%
rename from cmds/statsd/src/DropboxWriter.cpp
rename to cmds/statsd/src/storage/DropboxWriter.cpp
index b72e530..e59bdbd 100644
--- a/cmds/statsd/src/DropboxWriter.cpp
+++ b/cmds/statsd/src/storage/DropboxWriter.cpp
@@ -16,12 +16,12 @@
 
 #include <android/os/DropBoxManager.h>
 
-#include "DropboxWriter.h"
+#include "storage/DropboxWriter.h"
 
-using android::String16;
 using android::binder::Status;
 using android::os::DropBoxManager;
 using android::sp;
+using android::String16;
 using std::vector;
 
 namespace android {
diff --git a/cmds/statsd/src/DropboxWriter.h b/cmds/statsd/src/storage/DropboxWriter.h
similarity index 100%
rename from cmds/statsd/src/DropboxWriter.h
rename to cmds/statsd/src/storage/DropboxWriter.h
diff --git a/cmds/statsd/tests/AnomalyMonitor_test.cpp b/cmds/statsd/tests/AnomalyMonitor_test.cpp
index d5b6811..59fa160 100644
--- a/cmds/statsd/tests/AnomalyMonitor_test.cpp
+++ b/cmds/statsd/tests/AnomalyMonitor_test.cpp
@@ -12,9 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
-
-#include "../src/AnomalyMonitor.h"
+#include "anomaly/AnomalyMonitor.h"
 
 #include <gtest/gtest.h>
 
diff --git a/cmds/statsd/tests/ConditionTracker_test.cpp b/cmds/statsd/tests/ConditionTracker_test.cpp
index f8b0fd0..2935ac7 100644
--- a/cmds/statsd/tests/ConditionTracker_test.cpp
+++ b/cmds/statsd/tests/ConditionTracker_test.cpp
@@ -12,11 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
+#include "condition/condition_util.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 #include <gtest/gtest.h>
-#include "../src/condition/condition_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 #include <stdio.h>
 #include <vector>
diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp
new file mode 100644
index 0000000..aa896ca
--- /dev/null
+++ b/cmds/statsd/tests/ConfigManager_test.cpp
@@ -0,0 +1,156 @@
+// Copyright (C) 2017 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 "src/config/ConfigManager.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <stdio.h>
+#include <iostream>
+
+using namespace android;
+using namespace android::os::statsd;
+using namespace testing;
+using namespace std;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static ostream& operator<<(ostream& os, const StatsdConfig& config) {
+    return os << "StatsdConfig{id=" << config.config_id() << "}";
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
+
+/**
+ * Mock ConfigListener
+ */
+class MockListener : public ConfigListener {
+public:
+    MOCK_METHOD2(OnConfigUpdated, void(const ConfigKey& key, const StatsdConfig& config));
+    MOCK_METHOD1(OnConfigRemoved, void(const ConfigKey& key));
+};
+
+/**
+ * Validate that the ConfigKey is the one we wanted.
+ */
+MATCHER_P2(ConfigKeyEq, uid, name, "") {
+    return arg.GetUid() == uid && arg.GetName() == name;
+}
+
+/**
+ * Validate that the StatsdConfig is the one we wanted.
+ */
+MATCHER_P(StatsdConfigEq, configId, "") {
+    return arg.config_id() == configId;
+}
+
+/**
+ * Test the addOrUpdate and remove methods
+ */
+TEST(ConfigManagerTest, TestAddUpdateRemove) {
+    sp<MockListener> listener = new StrictMock<MockListener>();
+
+    sp<ConfigManager> manager = new ConfigManager();
+    manager->AddListener(listener);
+
+    StatsdConfig config91;
+    config91.set_config_id(91);
+    StatsdConfig config92;
+    config92.set_config_id(92);
+    StatsdConfig config93;
+    config93.set_config_id(93);
+    StatsdConfig config94;
+    config94.set_config_id(94);
+
+    {
+        InSequence s;
+
+        // The built-in fake one.
+        // TODO: Remove this when we get rid of the fake one, and make this
+        // test loading one from disk somewhere.
+        EXPECT_CALL(*(listener.get()),
+                    OnConfigUpdated(ConfigKeyEq(0, "fake"), StatsdConfigEq(12345)))
+                .RetiresOnSaturation();
+        manager->Startup();
+
+        // Add another one
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq(91)))
+                .RetiresOnSaturation();
+        manager->UpdateConfig(ConfigKey(1, "zzz"), config91);
+
+        // Update It
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "zzz"), StatsdConfigEq(92)))
+                .RetiresOnSaturation();
+        manager->UpdateConfig(ConfigKey(1, "zzz"), config92);
+
+        // Add one with the same uid but a different name
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(1, "yyy"), StatsdConfigEq(93)))
+                .RetiresOnSaturation();
+        manager->UpdateConfig(ConfigKey(1, "yyy"), config93);
+
+        // Add one with the same name but a different uid
+        EXPECT_CALL(*(listener.get()), OnConfigUpdated(ConfigKeyEq(2, "zzz"), StatsdConfigEq(94)))
+                .RetiresOnSaturation();
+        manager->UpdateConfig(ConfigKey(2, "zzz"), config94);
+
+        // Remove (1,yyy)
+        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, "yyy")))
+                .RetiresOnSaturation();
+        manager->RemoveConfig(ConfigKey(1, "yyy"));
+
+        // Remove (2,zzz)
+        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "zzz")))
+                .RetiresOnSaturation();
+        manager->RemoveConfig(ConfigKey(2, "zzz"));
+
+        // Remove (1,zzz)
+        EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(1, "zzz")))
+                .RetiresOnSaturation();
+        manager->RemoveConfig(ConfigKey(1, "zzz"));
+
+        // Remove (2,zzz) again and we shouldn't get the callback
+        manager->RemoveConfig(ConfigKey(2, "zzz"));
+    }
+}
+
+/**
+ * Test removing all of the configs for a uid.
+ */
+TEST(ConfigManagerTest, TestRemoveUid) {
+    sp<MockListener> listener = new StrictMock<MockListener>();
+
+    sp<ConfigManager> manager = new ConfigManager();
+    manager->AddListener(listener);
+
+    StatsdConfig config;
+
+    EXPECT_CALL(*(listener.get()), OnConfigUpdated(_, _)).Times(6);
+    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "xxx")));
+    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "yyy")));
+    EXPECT_CALL(*(listener.get()), OnConfigRemoved(ConfigKeyEq(2, "zzz")));
+
+    manager->Startup();
+    manager->UpdateConfig(ConfigKey(1, "aaa"), config);
+    manager->UpdateConfig(ConfigKey(2, "xxx"), config);
+    manager->UpdateConfig(ConfigKey(2, "yyy"), config);
+    manager->UpdateConfig(ConfigKey(2, "zzz"), config);
+    manager->UpdateConfig(ConfigKey(3, "bbb"), config);
+
+    manager->RemoveConfigs(2);
+}
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 6069801..3bc9862 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -12,15 +12,14 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "matchers/matcher_util.h"
+#include "stats_util.h"
 
 #include <gtest/gtest.h>
 #include <log/log_event_list.h>
 #include <log/log_read.h>
 #include <log/logprint.h>
-#include "../src/matchers/matcher_util.h"
-#include "../src/stats_util.h"
-#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
 #include <stdio.h>
 
diff --git a/cmds/statsd/tests/LogReader_test.cpp b/cmds/statsd/tests/LogReader_test.cpp
index 2002143..7ce1d6a 100644
--- a/cmds/statsd/tests/LogReader_test.cpp
+++ b/cmds/statsd/tests/LogReader_test.cpp
@@ -12,8 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
-
 #include <gtest/gtest.h>
 
 #include <stdio.h>
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 673c156..32661dc 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -12,14 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
-
 #include <gtest/gtest.h>
-#include "../src/condition/ConditionTracker.h"
-#include "../src/matchers/LogMatchingTracker.h"
-#include "../src/metrics/CountMetricProducer.h"
-#include "../src/metrics/MetricProducer.h"
-#include "../src/metrics/metrics_manager_util.h"
+
+#include "src/condition/ConditionTracker.h"
+#include "src/matchers/LogMatchingTracker.h"
+#include "src/metrics/CountMetricProducer.h"
+#include "src/metrics/MetricProducer.h"
+#include "src/metrics/metrics_manager_util.h"
 
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index b6f1449..f9a90e4 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#define LOG_TAG "statsd_test"
+#include "packages/UidMap.h"
 
 #include <gtest/gtest.h>
-#include "../src/UidMap.h"
+
 #include <stdio.h>
 
 using namespace android;
@@ -66,4 +66,4 @@
 }
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
\ No newline at end of file
+#endif
diff --git a/cmds/statsd/tests/indexed_priority_queue_test.cpp b/cmds/statsd/tests/indexed_priority_queue_test.cpp
index 74a482e..600b953 100644
--- a/cmds/statsd/tests/indexed_priority_queue_test.cpp
+++ b/cmds/statsd/tests/indexed_priority_queue_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "../src/indexed_priority_queue.h"
+#include "src/anomaly/indexed_priority_queue.h"
 
 #include <gtest/gtest.h>