Add basic logging infrastructure for bugreports

Test: as follows
    - built, flashed, booted
    - "adb shell dumpsys netd" shows logs
    - tests/runtests.sh passes
Change-Id: I0e44da7f9a9cc53074ffc396b958e9e2dbcd2603
diff --git a/libnetdutils/include/netdutils/Log.h b/libnetdutils/include/netdutils/Log.h
new file mode 100644
index 0000000..7a68a8f
--- /dev/null
+++ b/libnetdutils/include/netdutils/Log.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2018 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 NETUTILS_LOG_H
+#define NETUTILS_LOG_H
+
+#include <chrono>
+#include <deque>
+#include <shared_mutex>
+#include <string>
+
+#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
+
+#include <netdutils/Status.h>
+
+namespace android {
+namespace netdutils {
+
+class LogEntry {
+  public:
+    LogEntry() = default;
+    LogEntry(const LogEntry&) = default;
+    LogEntry(LogEntry&&) = default;
+    ~LogEntry() = default;
+    LogEntry& operator=(const LogEntry&) = default;
+    LogEntry& operator=(LogEntry&&) = default;
+
+    std::string toString() const;
+
+    ///
+    // Helper methods that make it easy to build up a LogEntry message.
+    // If performance becomes a factor the implementations could be inlined.
+    ///
+    LogEntry& message(const std::string& message);
+
+    // For calling with __FUNCTION__.
+    LogEntry& function(const std::string& function_name);
+    // For calling with __PRETTY_FUNCTION__.
+    LogEntry& prettyFunction(const std::string& pretty_function);
+
+    // Convenience methods for each of the common types of function arguments.
+    LogEntry& arg(const std::string& val);
+    LogEntry& arg(const std::vector<int32_t>& val);
+    LogEntry& arg(const std::vector<uint8_t>& val);
+    LogEntry& arg(const std::vector<std::string>& val);
+    LogEntry& arg(bool val);
+    template <class T>
+    LogEntry& arg(T val) {
+        mArgs.push_back(std::to_string(val));
+        return *this;
+    }
+
+    // Some things can return more than one value, or have multiple output
+    // parameters, so each of these adds to the mReturns vector.
+    LogEntry& returns(const std::string& rval);
+    LogEntry& returns(const Status& status);
+    LogEntry& returns(bool rval);
+    template <class T>
+    LogEntry& returns(T val) {
+        mReturns.push_back(std::to_string(val));
+        return *this;
+    }
+
+    LogEntry& withUid(uid_t uid);
+
+    // Append the duration computed since the creation of this instance.
+    LogEntry& withAutomaticDuration();
+    // Append the string-ified duration computed by some other means.
+    LogEntry& withDuration(const std::string& duration);
+
+  private:
+    std::chrono::steady_clock::time_point mStart = std::chrono::steady_clock::now();
+    std::string mMsg{};
+    std::string mFunc{};
+    std::vector<std::string> mArgs{};
+    std::vector<std::string> mReturns{};
+    std::string mUid{};
+    std::string mDuration{};
+};
+
+class Log {
+  public:
+    Log() = delete;
+    Log(const std::string& tag) : Log(tag, MAX_ENTRIES) {}
+    Log(const std::string& tag, size_t maxEntries) : mTag(tag), mMaxEntries(maxEntries) {}
+    Log(const Log&) = delete;
+    Log(Log&&) = delete;
+    ~Log();
+    Log& operator=(const Log&) = delete;
+    Log& operator=(Log&&) = delete;
+
+    LogEntry newEntry() const { return LogEntry(); }
+
+    // Record a log entry in internal storage only.
+    void log(const std::string& entry) { record(Level::LOG, entry); }
+    template <size_t n>
+    void log(const char entry[n]) { log(std::string(entry)); }
+    void log(const LogEntry& entry) { log(entry.toString()); }
+    void log(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
+        using ::android::base::StringAppendV;
+        std::string result;
+        va_list ap;
+        va_start(ap, fmt);
+        StringAppendV(&result, fmt, ap);
+        va_end(ap);
+        log(result);
+    }
+
+    // Record a log entry in internal storage and to ALOGI as well.
+    void info(const std::string& entry) { record(Level::INFO, entry); }
+    template <size_t n>
+    void info(const char entry[n]) { info(std::string(entry)); }
+    void info(const LogEntry& entry) { info(entry.toString()); }
+    void info(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
+        using ::android::base::StringAppendV;
+        std::string result;
+        va_list ap;
+        va_start(ap, fmt);
+        StringAppendV(&result, fmt, ap);
+        va_end(ap);
+        info(result);
+    }
+
+    // Record a log entry in internal storage and to ALOGW as well.
+    void warn(const std::string& entry) { record(Level::WARN, entry); }
+    template <size_t n>
+    void warn(const char entry[n]) { warn(std::string(entry)); }
+    void warn(const LogEntry& entry) { warn(entry.toString()); }
+    void warn(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
+        using ::android::base::StringAppendV;
+        std::string result;
+        va_list ap;
+        va_start(ap, fmt);
+        StringAppendV(&result, fmt, ap);
+        va_end(ap);
+        warn(result);
+    }
+
+    // Record a log entry in internal storage and to ALOGE as well.
+    void error(const std::string& entry) { record(Level::ERROR, entry); }
+    template <size_t n>
+    void error(const char entry[n]) { error(std::string(entry)); }
+    void error(const LogEntry& entry) { error(entry.toString()); }
+    void error(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))) {
+        using ::android::base::StringAppendV;
+        std::string result;
+        va_list ap;
+        va_start(ap, fmt);
+        StringAppendV(&result, fmt, ap);
+        va_end(ap);
+        error(result);
+    }
+
+    // Iterates over every entry in the log in chronological order. Operates
+    // on a copy of the log entries, and so perEntryFn may itself call one of
+    // the logging functions if needed.
+    void forEachEntry(const std::function<void(const std::string&)>& perEntryFn) const;
+
+  private:
+    static constexpr const size_t MAX_ENTRIES = 750U;
+    const std::string mTag;
+    const size_t mMaxEntries;
+
+    // The LOG level adds an entry to mEntries but does not output the message
+    // to the system log. All other levels append to mEntries and output to the
+    // the system log.
+    enum class Level {
+        LOG,
+        INFO,
+        WARN,
+        ERROR,
+    };
+
+    void record(Level lvl, const std::string& entry);
+
+    mutable std::shared_mutex mLock;
+    std::deque<const std::string> mEntries;  // GUARDED_BY(mLock), when supported
+};
+
+}  // namespace netdutils
+}  // namespace android
+
+#endif /* NETUTILS_LOG_H */