Build the Vulkan server

Bug: 171711491

TODO: Flesh out Framebuffer, ColorBuffer, RenderControl
TODO: Make sure feature control flags are set properly on init.
TODO: Implement various System related things like program and launcher
directory, env variable setting.

Change-Id: I126b9a7c3dcad6318e20e82eed1b6c774827804d
diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt
index 3f20bd2..e0b7bb3 100644
--- a/base/CMakeLists.txt
+++ b/base/CMakeLists.txt
@@ -1,8 +1,26 @@
-add_library(
-    gfxstreambase
+set(gfxstream-base-common-sources
     MemStream.cpp
+    MessageChannel.cpp
+    PathUtils.cpp
+    SharedLibrary.cpp
     Stream.cpp
     StreamSerializing.cpp
-    SubAllocator.cpp)
+    SubAllocator.cpp
+    System.cpp
+    Tracing.cpp)
+set(gfxstream-base-windows-sources
+    Win32UnicodeString.cpp)
+
+if (WIN32)
+add_library(
+    gfxstream-base
+    ${gfxstream-base-common-sources}
+    ${gfxstream-base-windows-sources})
+else()
+add_library(
+    gfxstream-base
+    ${gfxstream-base-common-sources})
+endif()
+
 target_include_directories(
-    gfxstreambase PUBLIC ../)
+    gfxstream-base PUBLIC ../)
diff --git a/base/Compiler.h b/base/Compiler.h
new file mode 100644
index 0000000..ddfd992
--- /dev/null
+++ b/base/Compiler.h
@@ -0,0 +1,39 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#pragma once
+
+// Use this inside a class declaration to ensure that the corresponding objects
+// cannot be copy-constructed or assigned. For example:
+//
+//   class Foo {
+//       ....
+//       DISALLOW_COPY_AND_ASSIGN(Foo)
+//       ....
+//   };
+//
+// Note: this macro is sometimes defined in 3rd-party libs, so let's check first
+#ifndef DISALLOW_COPY_AND_ASSIGN
+
+#define DISALLOW_COPY_AND_ASSIGN(T) \
+    T(const T& other) = delete; \
+    T& operator=(const T& other) = delete
+
+#endif
+
+#ifndef DISALLOW_COPY_ASSIGN_AND_MOVE
+
+#define DISALLOW_COPY_ASSIGN_AND_MOVE(T) \
+    DISALLOW_COPY_AND_ASSIGN(T); \
+    T(T&&) = delete; \
+    T& operator=(T&&) = delete
+
+#endif
diff --git a/base/ConditionVariable.h b/base/ConditionVariable.h
new file mode 100644
index 0000000..3094a8e
--- /dev/null
+++ b/base/ConditionVariable.h
@@ -0,0 +1,206 @@
+// Copyright (C) 2014 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 "base/Compiler.h"
+#include "base/Lock.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+#include <assert.h>
+
+namespace android {
+namespace base {
+
+// A class that implements a condition variable, which can be used in
+// association with a Lock to blocking-wait for specific conditions.
+// Useful to implement various synchronization data structures.
+class ConditionVariable {
+public:
+    // A set of functions to efficiently unlock the lock used with
+    // the current condition variable and signal or broadcast it.
+    //
+    // The functions are needed because on some platforms (Posix) it's more
+    // efficient to signal the variable before unlocking mutex, while on others
+    // (Windows) it's exactly the opposite. Functions implement the best way
+    // for each platform and abstract it out from the user.
+    void signalAndUnlock(StaticLock* lock);
+    void signalAndUnlock(AutoLock* lock);
+
+    void broadcastAndUnlock(StaticLock* lock);
+    void broadcastAndUnlock(AutoLock* lock);
+
+    void wait(AutoLock* userLock) {
+        assert(userLock->mLocked);
+        wait(&userLock->mLock);
+    }
+
+    //
+    // Convenience functions to get rid of the loop in condition variable usage
+    // Instead of hand-writing a loop, e.g.
+    //
+    //      while (mRefCount < 3) {
+    //          mCv.wait(&mLock);
+    //      }
+    //
+    // use the following two wait() overloads:
+    //
+    //      mCv.wait(&mLock, [this]() { return mRefCount >= 3; });
+    //
+    // Parameters:
+    // |lock| - a Lock or AutoLock pointer used with the condition variable.
+    // |pred| - a functor predicate that's compatible with "bool pred()"
+    //          signature and returns a condition when one should stop waiting.
+    //
+
+    template <class Predicate>
+    void wait(StaticLock* lock, Predicate pred) {
+        while (!pred()) {
+            this->wait(lock);
+        }
+    }
+
+    template <class Predicate>
+    void wait(AutoLock* lock, Predicate pred) {
+        this->wait(&lock->mLock, pred);
+    }
+
+#ifdef _WIN32
+
+    ConditionVariable() {
+        ::InitializeConditionVariable(&mCond);
+    }
+
+    // There's no special function to destroy CONDITION_VARIABLE in Windows.
+    ~ConditionVariable() = default;
+
+    // Wait until the condition variable is signaled. Note that spurious
+    // wakeups are always a possibility, so always check the condition
+    // in a loop, i.e. do:
+    //
+    //    while (!condition) { condVar.wait(&lock); }
+    //
+    // instead of:
+    //
+    //    if (!condition) { condVar.wait(&lock); }
+    //
+    void wait(StaticLock* userLock) {
+        ::SleepConditionVariableSRW(&mCond, &userLock->mLock, INFINITE, 0);
+    }
+
+    bool timedWait(StaticLock *userLock, uint64_t waitUntilUs) {
+        const auto now = System::get()->getUnixTimeUs();
+        const auto timeout =
+                std::max<uint64_t>(0, waitUntilUs  - now) / 1000;
+        return ::SleepConditionVariableSRW(
+                    &mCond, &userLock->mLock, timeout, 0) != 0;
+    }
+
+    // Signal that a condition was reached. This will wake at least (and
+    // preferrably) one waiting thread that is blocked on wait().
+    void signal() {
+        ::WakeConditionVariable(&mCond);
+    }
+
+    // Like signal(), but wakes all of the waiting threads.
+    void broadcast() {
+        ::WakeAllConditionVariable(&mCond);
+    }
+
+private:
+    CONDITION_VARIABLE mCond;
+
+#else  // !_WIN32
+
+    // Note: on Posix systems, make it a naive wrapper around pthread_cond_t.
+
+    ConditionVariable() {
+        pthread_cond_init(&mCond, NULL);
+    }
+
+    ~ConditionVariable() {
+        pthread_cond_destroy(&mCond);
+    }
+
+    void wait(StaticLock* userLock) {
+        pthread_cond_wait(&mCond, &userLock->mLock);
+    }
+
+    bool timedWait(StaticLock* userLock, uint64_t waitUntilUs) {
+        timespec abstime;
+        abstime.tv_sec = waitUntilUs / 1000000LL;
+        abstime.tv_nsec = (waitUntilUs % 1000000LL) * 1000;
+        return pthread_cond_timedwait(&mCond, &userLock->mLock, &abstime) == 0;
+    }
+
+    void signal() {
+        pthread_cond_signal(&mCond);
+    }
+
+    void broadcast() {
+        pthread_cond_broadcast(&mCond);
+    }
+
+private:
+    pthread_cond_t mCond;
+
+#endif  // !_WIN32
+
+    DISALLOW_COPY_ASSIGN_AND_MOVE(ConditionVariable);
+};
+
+#ifdef _WIN32
+inline void ConditionVariable::signalAndUnlock(StaticLock* lock) {
+    lock->unlock();
+    signal();
+}
+inline void ConditionVariable::signalAndUnlock(AutoLock* lock) {
+    lock->unlock();
+    signal();
+}
+
+inline void ConditionVariable::broadcastAndUnlock(StaticLock* lock) {
+    lock->unlock();
+    broadcast();
+}
+inline void ConditionVariable::broadcastAndUnlock(AutoLock* lock) {
+    lock->unlock();
+    broadcast();
+}
+#else  // !_WIN32
+inline void ConditionVariable::signalAndUnlock(StaticLock* lock) {
+    signal();
+    lock->unlock();
+}
+inline void ConditionVariable::signalAndUnlock(AutoLock* lock) {
+    signal();
+    lock->unlock();
+}
+inline void ConditionVariable::broadcastAndUnlock(StaticLock* lock) {
+    broadcast();
+    lock->unlock();
+}
+inline void ConditionVariable::broadcastAndUnlock(AutoLock* lock) {
+    broadcast();
+    lock->unlock();
+}
+#endif  // !_WIN32
+
+}  // namespace base
+}  // namespace android
diff --git a/base/EntityManager.h b/base/EntityManager.h
new file mode 100644
index 0000000..d176114
--- /dev/null
+++ b/base/EntityManager.h
@@ -0,0 +1,568 @@
+// Copyright (C) 2019 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 "base/Lookup.h"
+#include "base/Optional.h"
+
+#include <functional>
+#include <unordered_map>
+#include <vector>
+
+#include <inttypes.h>
+#include <stdio.h>
+
+#define ENTITY_MANAGER_DEBUG 0
+
+#if ENTITY_MANAGER_DEBUG
+
+#define EM_DBG(fmt,...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
+
+#else
+#define EM_DBG(...)
+#endif
+
+#define INVALID_ENTITY_HANDLE 0
+#define INVALID_COMPONENT_HANDLE 0
+
+namespace android {
+namespace base {
+
+// EntityManager: A way to represent an abstrat space of objects with handles.
+// Each handle is associated with data of type Item for quick access from handles to data.
+// Otherwise, entity data is spread through ComponentManagers.
+template<size_t indexBits,
+         size_t generationBits,
+         size_t typeBits,
+         class Item>
+class EntityManager {
+public:
+
+    static_assert(64 == (indexBits + generationBits + typeBits),
+                  "bits of index, generation, and type must add to 64");
+
+    using EntityHandle = uint64_t;
+    using IteratorFunc = std::function<void(bool live, EntityHandle h, Item& item)>;
+    using ConstIteratorFunc = std::function<void(bool live, EntityHandle h, const Item& item)>;
+
+    static size_t getHandleIndex(EntityHandle h) {
+        return static_cast<size_t>(h & ((1ULL << indexBits) - 1ULL));
+    }
+
+    static size_t getHandleGeneration(EntityHandle h) {
+        return static_cast<size_t>(
+            (h >> indexBits) &
+            ((1ULL << generationBits) - 1ULL));
+    }
+
+    static size_t getHandleType(EntityHandle h) {
+        return static_cast<size_t>(
+            (h >> (indexBits + generationBits)) &
+            ((1ULL << typeBits) - 1ULL));
+        return h & ((1ULL << indexBits) - 1ULL);
+    }
+
+    static EntityHandle makeHandle(
+        size_t index,
+        size_t generation,
+        size_t type) {
+        EntityHandle res = index;
+        res |= generation << indexBits;
+        res |= type << (indexBits + generationBits);
+        return res;
+    }
+
+    static EntityHandle withIndex(EntityHandle h, size_t i) {
+        return makeHandle(i, getHandleGeneration(h), getHandleType(h));
+    }
+
+    static EntityHandle withGeneration(EntityHandle h, size_t nextGen) {
+        return makeHandle(getHandleIndex(h), nextGen, getHandleType(h));
+    }
+
+    static EntityHandle withType(EntityHandle h, size_t newType) {
+        return makeHandle(getHandleIndex(h), getHandleGeneration(h), newType);
+    }
+
+    EntityManager() : EntityManager(0) { }
+
+    ~EntityManager() { clear(); }
+
+    struct EntityEntry {
+        EntityHandle handle = 0;
+        size_t nextFreeIndex = 0;
+        // 0 is a special generation for brand new entries
+        // that are not used yet
+        size_t liveGeneration = 1;
+        Item item;
+    };
+
+    void clear() {
+        mEntries.clear();
+        mFirstFreeIndex = 0;
+        mLiveEntries = 0;
+    }
+
+    EntityHandle add(const Item& item, size_t type) {
+
+        if (!type) return INVALID_ENTITY_HANDLE;
+
+        size_t maxElements = (1ULL << indexBits);
+        if (mLiveEntries == maxElements) return INVALID_ENTITY_HANDLE;
+
+        size_t newIndex = mFirstFreeIndex;
+
+        EM_DBG("newIndex/firstFree: %zu type: %zu", newIndex, type);
+
+        size_t neededCapacity = newIndex + 1;
+        if (maxElements < neededCapacity) return INVALID_ENTITY_HANDLE;
+
+        size_t currentCapacity = mEntries.size();
+        size_t nextCapacity = neededCapacity << 1;
+        if (nextCapacity > maxElements) nextCapacity = maxElements;
+
+        EM_DBG("needed/current/next capacity: %zu %zu %zu",
+               neededCapacity,
+               currentCapacity,
+               nextCapacity);
+
+        if (neededCapacity > mEntries.size()) {
+            mEntries.resize(nextCapacity);
+            for (size_t i = currentCapacity; i < nextCapacity; ++i) {
+                mEntries[i].handle = makeHandle(i, 0, type);
+                mEntries[i].nextFreeIndex = i + 1;
+                EM_DBG("new un-init entry: index %zu nextFree %zu",
+                       i, i + 1);
+            }
+        }
+
+        mEntries[newIndex].handle =
+            makeHandle(newIndex, mEntries[newIndex].liveGeneration, type);
+        mEntries[newIndex].item = item;
+
+        mFirstFreeIndex = mEntries[newIndex].nextFreeIndex;
+        EM_DBG("created. new first free: %zu", mFirstFreeIndex);
+
+        ++mLiveEntries;
+
+        EM_DBG("result handle: 0x%llx", (unsigned long long)mEntries[newIndex].handle);
+
+        return mEntries[newIndex].handle;
+    }
+
+    EntityHandle addFixed(EntityHandle fixedHandle, const Item& item, size_t type) {
+        // 3 cases:
+        // 1. handle is not allocated and doesn't correspond to mFirstFreeIndex
+        bool isFreeListNonHead = false;
+        // 2. handle already exists (replace)
+        bool isAlloced = false;
+        // 3. index(handle) == mFirstFreeIndex
+        bool isFreeListHead = false;
+
+        if (!type) return INVALID_ENTITY_HANDLE;
+
+        size_t maxElements = (1ULL << indexBits);
+        if (mLiveEntries == maxElements) return INVALID_ENTITY_HANDLE;
+
+        size_t newIndex = getHandleIndex(fixedHandle);
+
+        EM_DBG("newIndex/firstFree: %zu type: %zu", newIndex, type);
+
+        size_t neededCapacity = newIndex + 1;
+
+        if (maxElements < neededCapacity) return INVALID_ENTITY_HANDLE;
+
+        size_t currentCapacity = mEntries.size();
+        size_t nextCapacity = neededCapacity << 1;
+        if (nextCapacity > maxElements) nextCapacity = maxElements;
+
+        EM_DBG("needed/current/next capacity: %zu %zu %zu",
+               neededCapacity,
+               currentCapacity,
+               nextCapacity);
+
+        if (neededCapacity > mEntries.size()) {
+            mEntries.resize(nextCapacity);
+            for (size_t i = currentCapacity; i < nextCapacity; ++i) {
+                mEntries[i].handle = makeHandle(i, 0, type);
+                mEntries[i].nextFreeIndex = i + 1;
+                EM_DBG("new un-init entry: index %zu nextFree %zu",
+                       i, i + 1);
+            }
+        }
+
+        // Now we ensured that there is enough space to talk about the entry of
+        // this |fixedHandle|.
+        if (mFirstFreeIndex == newIndex) {
+            isFreeListHead = true;
+        } else {
+            auto& entry = mEntries[newIndex];
+            if (entry.liveGeneration == getHandleGeneration(entry.handle)) {
+                isAlloced = true;
+            } else {
+                isFreeListNonHead = true;
+            }
+        }
+
+        mEntries[newIndex].handle = fixedHandle;
+        mEntries[newIndex].liveGeneration = getHandleGeneration(fixedHandle);
+        mEntries[newIndex].item = item;
+
+        EM_DBG("new index: %zu", newIndex);
+
+        if (isFreeListHead) {
+
+            EM_DBG("first free index reset from %zu to %zu",
+                    mFirstFreeIndex, mEntries[newIndex].nextFreeIndex);
+
+            mFirstFreeIndex = mEntries[newIndex].nextFreeIndex;
+
+            ++mLiveEntries;
+
+        } else if (isAlloced) {
+            // Already replaced whatever is there, and since it's already allocated,
+            // no need to update freelist.
+            EM_DBG("entry at %zu already alloced. replacing.", newIndex);
+        } else if (isFreeListNonHead) {
+            // Go through the freelist and skip over the entry we just added.
+            size_t prevEntryIndex = mFirstFreeIndex;
+
+            EM_DBG("in free list but not head. reorganizing freelist. "
+                   "start at %zu -> %zu",
+                   mFirstFreeIndex, mEntries[prevEntryIndex].nextFreeIndex);
+
+            while (mEntries[prevEntryIndex].nextFreeIndex != newIndex) {
+                EM_DBG("next: %zu -> %zu",
+                       prevEntryIndex,
+                       mEntries[prevEntryIndex].nextFreeIndex);
+                prevEntryIndex =
+                    mEntries[prevEntryIndex].nextFreeIndex;
+            }
+
+            EM_DBG("finished. set prev entry %zu to new entry's next, %zu",
+                    prevEntryIndex, mEntries[newIndex].nextFreeIndex);
+
+            mEntries[prevEntryIndex].nextFreeIndex =
+                mEntries[newIndex].nextFreeIndex;
+
+            ++mLiveEntries;
+        }
+
+        return fixedHandle;
+    }
+    void remove(EntityHandle h) {
+
+        if (get(h) == nullptr) return;
+
+        size_t index = getHandleIndex(h);
+
+        EM_DBG("remove handle: 0x%llx -> index %zu", (unsigned long long)h, index);
+
+        auto& entry = mEntries[index];
+
+        EM_DBG("handle gen: %zu entry gen: %zu", getHandleGeneration(h), entry.liveGeneration);
+
+        ++entry.liveGeneration;
+        if ((entry.liveGeneration == 0) ||
+            (entry.liveGeneration == (1ULL << generationBits))) {
+            entry.liveGeneration = 1;
+        }
+
+        entry.nextFreeIndex = mFirstFreeIndex;
+
+        mFirstFreeIndex = index;
+
+        EM_DBG("new first free: %zu next free: %zu", mFirstFreeIndex, entry.nextFreeIndex);
+
+        --mLiveEntries;
+    }
+
+    Item* get(EntityHandle h) {
+        size_t index = getHandleIndex(h);
+        if (index >= mEntries.size()) return nullptr;
+
+        auto& entry = mEntries[index];
+        if (entry.liveGeneration != getHandleGeneration(h)) return nullptr;
+
+        return &entry.item;
+    }
+
+    bool isLive(EntityHandle h) const {
+        size_t index = getHandleIndex(h);
+        if (index >= mEntries.size()) return false;
+
+        const auto& entry = mEntries[index];
+
+        return (entry.liveGeneration == getHandleGeneration(h));
+    }
+
+    void forEachEntry(IteratorFunc func) {
+        for (auto& entry: mEntries) {
+            auto handle = entry.handle;
+            bool live = isLive(handle);
+            auto& item = entry.item;
+            func(live, handle, item);
+        }
+    }
+
+    void forEachLiveEntry(IteratorFunc func) {
+        for (auto& entry: mEntries) {
+            auto handle = entry.handle;
+            bool live = isLive(handle);
+
+            if (!live) continue;
+
+            auto& item = entry.item;
+            func(live, handle, item);
+        }
+    }
+
+    void forEachLiveEntry_const(ConstIteratorFunc func) const {
+        for (auto& entry: mEntries) {
+            auto handle = entry.handle;
+            bool live = isLive(handle);
+
+            if (!live) continue;
+
+            const auto& item = entry.item;
+            func(live, handle, item);
+        }
+    }
+
+private:
+    EntityManager(size_t initialItems) :
+        mEntries(initialItems),
+        mFirstFreeIndex(0),
+        mLiveEntries(0) { }
+
+    std::vector<EntityEntry> mEntries;
+    size_t mFirstFreeIndex;
+    size_t mLiveEntries;
+};
+
+// Tracks components over a given space of entities.
+// Looking up by entity index is slower, but takes less space overall versus
+// a flat array that parallels the entities.
+template<size_t indexBits,
+         size_t generationBits,
+         size_t typeBits,
+         class Data>
+class ComponentManager {
+public:
+
+    static_assert(64 == (indexBits + generationBits + typeBits),
+                  "bits of index, generation, and type must add to 64");
+
+    using ComponentHandle = uint64_t;
+    using EntityHandle = uint64_t;
+    using ComponentIteratorFunc = std::function<void(bool, ComponentHandle componentHandle, EntityHandle entityHandle, Data& data)>;
+    using ConstComponentIteratorFunc = std::function<void(bool, ComponentHandle componentHandle, EntityHandle entityHandle, const Data& data)>;
+
+    // Adds the given |data| and associates it with EntityHandle.
+    // We can also opt-in to immediately tracking the handle in the reverse mapping,
+    // which has an upfront cost in runtime.
+    // Many uses of ComponentManager don't really need to track the associated entity handle,
+    // so it is opt-in.
+
+    ComponentHandle add(
+        EntityHandle h,
+        const Data& data,
+        size_t type,
+        bool tracked = false) {
+
+        InternalItem item = { h, data, tracked };
+        auto res = static_cast<ComponentHandle>(mData.add(item, type));
+
+        if (tracked) {
+            mEntityToComponentMap[h] = res;
+        }
+
+        return res;
+    }
+
+    void clear() {
+        mData.clear();
+        mEntityToComponentMap.clear();
+    }
+
+    // If we didn't explicitly track, just fail.
+    ComponentHandle getComponentHandle(EntityHandle h) const {
+        auto componentHandlePtr = android::base::find(mEntityToComponentMap, h);
+        if (!componentHandlePtr) return INVALID_COMPONENT_HANDLE;
+        return *componentHandlePtr;
+    }
+
+    EntityHandle getEntityHandle(ComponentHandle h) const {
+        return mData.get(h)->entityHandle;
+    }
+
+    void removeByEntity(EntityHandle h) {
+        auto componentHandle = getComponentHandle(h);
+        removeByComponent(componentHandle);
+    }
+
+    void removeByComponent(ComponentHandle h) {
+        auto item = mData.get(h);
+
+        if (!item) return;
+        if (item->tracked) {
+            mEntityToComponentMap.erase(item->entityHandle);
+        }
+
+        mData.remove(h);
+    }
+
+    Data* getByEntity(EntityHandle h) {
+        return getByComponent(getComponentHandle(h));
+    }
+
+    Data* getByComponent(ComponentHandle h) {
+        auto item = mData.get(h);
+        if (!item) return nullptr;
+        return &(item->data);
+    }
+
+    void forEachComponent(ComponentIteratorFunc func) {
+        mData.forEachEntry(
+            [func](bool live, typename InternalEntityManager::EntityHandle componentHandle, InternalItem& item) {
+                func(live, componentHandle, item.entityHandle, item.data);
+        });
+    }
+
+    void forEachLiveComponent(ComponentIteratorFunc func) {
+        mData.forEachLiveEntry(
+            [func](bool live, typename InternalEntityManager::EntityHandle componentHandle, InternalItem& item) {
+                func(live, componentHandle, item.entityHandle, item.data);
+        });
+    }
+
+    void forEachLiveComponent_const(ConstComponentIteratorFunc func) const {
+        mData.forEachLiveEntry_const(
+            [func](bool live, typename InternalEntityManager::EntityHandle componentHandle, const InternalItem& item) {
+                func(live, componentHandle, item.entityHandle, item.data);
+        });
+    }
+
+private:
+    struct InternalItem {
+        EntityHandle entityHandle;
+        Data data;
+        bool tracked;
+    };
+
+    using InternalEntityManager = EntityManager<indexBits, generationBits, typeBits, InternalItem>;
+    using EntityToComponentMap = std::unordered_map<EntityHandle, ComponentHandle>;
+
+    mutable InternalEntityManager mData;
+    EntityToComponentMap mEntityToComponentMap;
+};
+
+// ComponentManager, but unpacked; uses the same index space as the associated
+// entities. Takes more space by default, but not more if all entities have this component.
+template<size_t indexBits,
+         size_t generationBits,
+         size_t typeBits,
+         class Data>
+class UnpackedComponentManager {
+public:
+    using ComponentHandle = uint64_t;
+    using EntityHandle = uint64_t;
+    using ComponentIteratorFunc =
+        std::function<void(bool, ComponentHandle componentHandle, EntityHandle entityHandle, Data& data)>;
+    using ConstComponentIteratorFunc =
+        std::function<void(bool, ComponentHandle componentHandle, EntityHandle entityHandle, const Data& data)>;
+
+    EntityHandle add(EntityHandle h, const Data& data) {
+
+        size_t index = indexOfEntity(h);
+
+        if (index + 1 > mItems.size()) {
+            mItems.resize((index + 1) * 2);
+        }
+
+        mItems[index].live = true;
+        mItems[index].handle = h;
+        mItems[index].data = data;
+
+        return h;
+    }
+
+    void clear() {
+        mItems.clear();
+    }
+
+    void remove(EntityHandle h) {
+        size_t index = indexOfEntity(h);
+        if (index >= mItems.size()) return;
+        mItems[index].live = false;
+    }
+
+    Data* get(EntityHandle h) {
+        size_t index = indexOfEntity(h);
+
+        if (index + 1 > mItems.size()) {
+            mItems.resize((index + 1) * 2);
+        }
+
+        auto item = mItems.data() + index;
+        if (!item->live) return nullptr;
+        return &item->data;
+    }
+
+    const Data* get_const(EntityHandle h) const {
+        size_t index = indexOfEntity(h);
+
+        if (index + 1 > mItems.size()) {
+            return nullptr;
+        }
+
+        auto item = mItems.data() + index;
+        if (!item->live) return nullptr;
+        return &item->data;
+    }
+
+    void forEachComponent(ComponentIteratorFunc func) {
+        for (auto& item : mItems) {
+            func(item.live, item.handle, item.handle, item.data);
+        }
+    }
+
+    void forEachLiveComponent(ComponentIteratorFunc func) {
+        for (auto& item : mItems) {
+            if (item.live) func(item.live, item.handle, item.handle, item.data);
+        }
+    }
+
+    void forEachLiveComponent_const(ConstComponentIteratorFunc func) const {
+        for (auto& item : mItems) {
+            if (item.live) func(item.live, item.handle, item.handle, item.data);
+        }
+    }
+
+private:
+    static size_t indexOfEntity(EntityHandle h) {
+        return EntityManager<indexBits, generationBits, typeBits, int>::getHandleIndex(h);
+    }
+
+    struct InternalItem {
+        bool live = false;
+        EntityHandle handle = 0;
+        Data data;
+    };
+
+    std::vector<InternalItem> mItems;
+};
+
+} // namespace android
+} // namespace base
diff --git a/base/Lock.h b/base/Lock.h
new file mode 100644
index 0000000..56fe7c5
--- /dev/null
+++ b/base/Lock.h
@@ -0,0 +1,230 @@
+// Copyright (C) 2014 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 "base/Compiler.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+#include <assert.h>
+
+namespace android {
+namespace base {
+
+class AutoLock;
+class AutoWriteLock;
+class AutoReadLock;
+
+// A wrapper class for mutexes only suitable for using in static context,
+// where it's OK to leak the underlying system object. Use Lock for scoped or
+// member locks.
+class StaticLock {
+public:
+    using AutoLock = android::base::AutoLock;
+
+    constexpr StaticLock() = default;
+
+    // Acquire the lock.
+    void lock() {
+#ifdef _WIN32
+        ::AcquireSRWLockExclusive(&mLock);
+#else
+        ::pthread_mutex_lock(&mLock);
+#endif
+    }
+
+    bool tryLock() {
+        bool ret = false;
+#ifdef _WIN32
+        ret = ::TryAcquireSRWLockExclusive(&mLock);
+#else
+        ret = ::pthread_mutex_trylock(&mLock) == 0;
+#endif
+        return ret;
+    }
+
+    // Release the lock.
+    void unlock() {
+#ifdef _WIN32
+        ::ReleaseSRWLockExclusive(&mLock);
+#else
+        ::pthread_mutex_unlock(&mLock);
+#endif
+    }
+
+protected:
+    friend class ConditionVariable;
+
+#ifdef _WIN32
+    // Benchmarks show that on Windows SRWLOCK performs a little bit better than
+    // CRITICAL_SECTION for uncontended mode and much better in case of
+    // contention.
+    SRWLOCK mLock = SRWLOCK_INIT;
+#else
+    pthread_mutex_t mLock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+    // Both POSIX threads and WinAPI don't allow move (undefined behavior).
+    DISALLOW_COPY_ASSIGN_AND_MOVE(StaticLock);
+};
+
+// Simple wrapper class for mutexes used in non-static context.
+class Lock : public StaticLock {
+public:
+    using StaticLock::AutoLock;
+
+    constexpr Lock() = default;
+#ifndef _WIN32
+    // The only difference is that POSIX requires a deallocation function call
+    // for its mutexes.
+    ~Lock() { ::pthread_mutex_destroy(&mLock); }
+#endif
+};
+
+class ReadWriteLock {
+public:
+    using AutoWriteLock = android::base::AutoWriteLock;
+    using AutoReadLock = android::base::AutoReadLock;
+
+#ifdef _WIN32
+    constexpr ReadWriteLock() = default;
+    ~ReadWriteLock() = default;
+    void lockRead() { ::AcquireSRWLockShared(&mLock); }
+    void unlockRead() { ::ReleaseSRWLockShared(&mLock); }
+    void lockWrite() { ::AcquireSRWLockExclusive(&mLock); }
+    void unlockWrite() { ::ReleaseSRWLockExclusive(&mLock); }
+
+private:
+    SRWLOCK mLock = SRWLOCK_INIT;
+#else   // !_WIN32
+    ReadWriteLock() { ::pthread_rwlock_init(&mLock, NULL); }
+    ~ReadWriteLock() { ::pthread_rwlock_destroy(&mLock); }
+    void lockRead() { ::pthread_rwlock_rdlock(&mLock); }
+    void unlockRead() { ::pthread_rwlock_unlock(&mLock); }
+    void lockWrite() { ::pthread_rwlock_wrlock(&mLock); }
+    void unlockWrite() { ::pthread_rwlock_unlock(&mLock); }
+
+private:
+    pthread_rwlock_t mLock;
+#endif  // !_WIN32
+
+    friend class ConditionVariable;
+    DISALLOW_COPY_ASSIGN_AND_MOVE(ReadWriteLock);
+};
+
+// Helper class to lock / unlock a mutex automatically on scope
+// entry and exit.
+// NB: not thread-safe (as opposed to the Lock class)
+class AutoLock {
+public:
+    AutoLock(StaticLock& lock) : mLock(lock) { mLock.lock(); }
+
+    AutoLock(AutoLock&& other) : mLock(other.mLock), mLocked(other.mLocked) {
+        other.mLocked = false;
+    }
+
+    void lock() {
+        assert(!mLocked);
+        mLock.lock();
+        mLocked = true;
+    }
+
+    void unlock() {
+        assert(mLocked);
+        mLock.unlock();
+        mLocked = false;
+    }
+
+    bool isLocked() const { return mLocked; }
+
+    ~AutoLock() {
+        if (mLocked) {
+            mLock.unlock();
+        }
+    }
+
+private:
+    StaticLock& mLock;
+    bool mLocked = true;
+
+    friend class ConditionVariable;
+    // Don't allow move because this class has a non-movable object.
+    DISALLOW_COPY_AND_ASSIGN(AutoLock);
+};
+
+class AutoWriteLock {
+public:
+    AutoWriteLock(ReadWriteLock& lock) : mLock(lock) { mLock.lockWrite(); }
+
+    void lockWrite() {
+        assert(!mWriteLocked);
+        mLock.lockWrite();
+        mWriteLocked = true;
+    }
+
+    void unlockWrite() {
+        assert(mWriteLocked);
+        mLock.unlockWrite();
+        mWriteLocked = false;
+    }
+
+    ~AutoWriteLock() {
+        if (mWriteLocked) {
+            mLock.unlockWrite();
+        }
+    }
+
+private:
+    ReadWriteLock& mLock;
+    bool mWriteLocked = true;
+    // This class has a non-movable object.
+    DISALLOW_COPY_ASSIGN_AND_MOVE(AutoWriteLock);
+};
+
+class AutoReadLock {
+public:
+    AutoReadLock(ReadWriteLock& lock) : mLock(lock) { mLock.lockRead(); }
+
+    void lockRead() {
+        assert(!mReadLocked);
+        mLock.lockRead();
+        mReadLocked = true;
+    }
+
+    void unlockRead() {
+        assert(mReadLocked);
+        mLock.unlockRead();
+        mReadLocked = false;
+    }
+
+    ~AutoReadLock() {
+        if (mReadLocked) {
+            mLock.unlockRead();
+        }
+    }
+
+private:
+    ReadWriteLock& mLock;
+    bool mReadLocked = true;
+    // This class has a non-movable object.
+    DISALLOW_COPY_ASSIGN_AND_MOVE(AutoReadLock);
+};
+
+}  // namespace base
+}  // namespace android
diff --git a/base/Lookup.h b/base/Lookup.h
new file mode 100644
index 0000000..a944590
--- /dev/null
+++ b/base/Lookup.h
@@ -0,0 +1,168 @@
+// Copyright 2016 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#pragma once
+
+#include "base/TypeTraits.h"
+
+#include <initializer_list>
+#include <set>
+#include <map>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+
+// A set of convenience functions for map and set lookups. They allow a simpler
+// syntax, e.g.
+//   if (auto val = find(map, "key")) {
+//       <process the value>
+//   }
+// ... or
+//   auto value = find(funcThatReturnsMap(), "other_key");
+//   if (!value) ...
+//
+// Note: these don't work for multimaps, as there's no single value
+//  to return (and, more importantly, as those are completely useless).
+
+namespace android {
+namespace base {
+
+// Helper predicates that check if the template argument is a map / set /
+// a mutlikey collection of any kind.
+// These are used as a constraints for the lookup functions to get better error
+// messages if the arguments don't support the map interface.
+template <class T>
+using is_any_map = std::integral_constant<
+        bool,
+        is_template_instantiation_of<T, std::map>::value ||
+                is_template_instantiation_of<T, std::unordered_map>::value>;
+
+template <class T>
+using is_any_set = std::integral_constant<
+        bool,
+        is_template_instantiation_of<T, std::set>::value ||
+                is_template_instantiation_of<T, std::unordered_set>::value>;
+
+template <class T>
+using is_any_multikey = std::integral_constant<
+        bool,
+        is_template_instantiation_of<T, std::multimap>::value ||
+                is_template_instantiation_of<T, std::unordered_multimap>::value ||
+                is_template_instantiation_of<T, std::multiset>::value ||
+                is_template_instantiation_of<T, std::unordered_multiset>::value>;
+
+template <class T, class = enable_if<is_any_map<T>>>
+const typename T::mapped_type* find(const T& map,
+                                    const typename T::key_type& key) {
+    const auto it = map.find(key);
+    if (it == map.end()) {
+        return nullptr;
+    }
+
+    return &it->second;
+}
+
+// Version that returns a modifiable value.
+template <class T, class = enable_if<is_any_map<T>>>
+typename T::mapped_type* find(T& map, const typename T::key_type& key) {
+    auto it = map.find(key);
+    if (it == map.end()) {
+        return nullptr;
+    }
+
+    return &it->second;
+}
+
+// Version with a default, returns a _copy_ because of the possible fallback
+// to a default - it might be destroyed after the call.
+template <class T,
+          class U = typename T::mapped_type,
+          class = enable_if_c<
+                  is_any_map<T>::value &&
+                  std::is_convertible<U, typename T::mapped_type>::value>>
+typename T::mapped_type findOrDefault(const T& map,
+                                      const typename T::key_type& key,
+                                      U&& defaultVal = {}) {
+    if (auto valPtr = find(map, key)) {
+        return *valPtr;
+    }
+    return std::forward<U>(defaultVal);
+}
+
+// Version that finds the first of the values passed in |keys| in the order they
+// are passed. E.g., the following code finds '2' as the first value in |keys|:
+//   set<int> s = {1, 2, 3};
+//   auto val = findFirstOf(s, {2, 1});
+//   EXPECT_EQ(2, *val);
+template <class T, class = enable_if<is_any_map<T>>>
+const typename T::mapped_type* findFirstOf(
+        const T& map,
+        std::initializer_list<typename T::key_type> keys) {
+    for (const auto& key : keys) {
+        if (const auto valPtr = find(map, key)) {
+            return valPtr;
+        }
+    }
+    return nullptr;
+}
+
+template <class T, class = enable_if<is_any_map<T>>>
+typename T::mapped_type* findFirstOf(
+        T& map,
+        std::initializer_list<typename T::key_type> keys) {
+    for (const auto& key : keys) {
+        if (const auto valPtr = find(map, key)) {
+            return valPtr;
+        }
+    }
+    return nullptr;
+}
+
+// Version that finds first of the passed |key| values or returns the
+// |defaultVal| if none were found.
+template <class T,
+          class U,
+          class = enable_if_c<
+                  is_any_map<T>::value &&
+                  std::is_convertible<U, typename T::mapped_type>::value>>
+typename T::mapped_type findFirstOfOrDefault(
+        const T& map,
+        std::initializer_list<typename T::key_type> keys,
+        U&& defaultVal) {
+    if (const auto valPtr = findFirstOf(map, keys)) {
+        return *valPtr;
+    }
+    return std::forward<U>(defaultVal);
+}
+
+template <class T,
+          class = enable_if_c<is_any_map<T>::value || is_any_set<T>::value ||
+                              is_any_multikey<T>::value>>
+bool contains(const T& c, const typename T::key_type& key) {
+    const auto it = c.find(key);
+    return it != c.end();
+}
+
+template <class T,
+          class = enable_if_c<is_any_map<T>::value || is_any_set<T>::value ||
+                              is_any_multikey<T>::value>>
+bool containsAnyOf(const T& c,
+                   std::initializer_list<typename T::key_type> keys) {
+    for (const auto& key : keys) {
+        if (contains(c, key)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/MemStream.cpp b/base/MemStream.cpp
index 6c5dbfb..d6dc641 100644
--- a/base/MemStream.cpp
+++ b/base/MemStream.cpp
@@ -19,6 +19,8 @@
 #include <algorithm>
 #include <utility>
 
+#include <string.h>
+
 namespace android {
 namespace base {
 
diff --git a/base/MessageChannel.cpp b/base/MessageChannel.cpp
new file mode 100644
index 0000000..ca29e2f
--- /dev/null
+++ b/base/MessageChannel.cpp
@@ -0,0 +1,121 @@
+// Copyright 2014 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 "base/MessageChannel.h"
+
+namespace android {
+namespace base {
+
+MessageChannelBase::MessageChannelBase(size_t capacity) : mCapacity(capacity) {}
+
+size_t MessageChannelBase::size() const {
+    AutoLock lock(mLock);
+    return mCount;
+}
+
+void MessageChannelBase::stop() {
+    android::base::AutoLock lock(mLock);
+    mStopped = true;
+    mCount = 0;
+    mCanRead.broadcast();
+    mCanWrite.broadcastAndUnlock(&lock);
+}
+
+bool MessageChannelBase::isStopped() const {
+    AutoLock lock(mLock);
+    return isStoppedLocked();
+}
+
+void MessageChannelBase::waitForEmpty() {
+    AutoLock lock(mLock);
+    while (mCount > 0) {
+        mCanWrite.wait(&lock);
+    }
+}
+
+size_t MessageChannelBase::beforeWrite() {
+    mLock.lock();
+    while (mCount >= mCapacity && !mStopped) {
+        mCanWrite.wait(&mLock);
+    }
+    // Return value is undefined if stopped, so let's save a branch and skip the
+    // check for it.
+    size_t result = mPos + mCount;
+    if (result >= mCapacity) {
+        result -= mCapacity;
+    }
+    return result;
+}
+
+Optional<size_t> MessageChannelBase::beforeTryWrite() {
+    mLock.lock();
+
+    if (mCount >= mCapacity || mStopped) {
+        return {};
+    }
+    size_t result = mPos + mCount;
+    if (result >= mCapacity) {
+        result -= mCapacity;
+    }
+    return result;
+}
+
+void MessageChannelBase::afterWrite(bool success) {
+    if (success) {
+        ++mCount;
+    }
+    mCanRead.signalAndUnlock(&mLock);
+}
+
+size_t MessageChannelBase::beforeRead() {
+    mLock.lock();
+    while (mCount == 0 && !mStopped) {
+        mCanRead.wait(&mLock);
+    }
+    return mPos; // return value is undefined if stopped, so let's save a branch
+}
+
+Optional<size_t> MessageChannelBase::beforeTryRead() {
+    mLock.lock();
+
+    if (mCount == 0 || mStopped) {
+        return {};
+    }
+    return mPos;
+}
+
+Optional<size_t> MessageChannelBase::beforeTimedRead(
+        uint64_t wallTimeUs) {
+    mLock.lock();
+
+    while (mCount == 0 && !mStopped) {
+        if (!mCanRead.timedWait(&mLock, wallTimeUs)) {
+            return {};
+        }
+    }
+    return mPos;
+}
+
+void MessageChannelBase::afterRead(bool success) {
+    if (success) {
+        if (++mPos == mCapacity) {
+            mPos = 0U;
+        }
+        --mCount;
+    }
+    mCanWrite.signalAndUnlock(&mLock);
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/MessageChannel.h b/base/MessageChannel.h
new file mode 100644
index 0000000..22bc648
--- /dev/null
+++ b/base/MessageChannel.h
@@ -0,0 +1,208 @@
+// Copyright 2014 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 "base/Optional.h"
+#include "base/ConditionVariable.h"
+#include "base/Lock.h"
+
+#include <utility>
+#include <stddef.h>
+
+namespace android {
+namespace base {
+
+// Base non-templated class used to reduce the amount of template
+// specialization.
+class MessageChannelBase {
+public:
+    // Get the current channel size
+    size_t size() const;
+
+    // Abort the currently pending operations and don't allow any other ones
+    void stop();
+
+    // Check if the channel is stopped.
+    bool isStopped() const;
+
+    // Block until the channel has no pending messages.
+    void waitForEmpty();
+
+protected:
+    // Constructor. |capacity| is the buffer capacity in messages.
+    MessageChannelBase(size_t capacity);
+
+    // Destructor.
+    ~MessageChannelBase() = default;
+
+    // Call this method in the sender thread before writing a new message.
+    // This returns the position of the available slot in the message array
+    // where to copy the new fixed-size message. After the copy, call
+    // afterWrite().
+    // If the channel is stopped, return value is undefined.
+    size_t beforeWrite();
+
+    // Same as beforeWrite(), but returns an empty optional if there was
+    // no room to write to instead of waiting for it.
+    // One still needs to call afterWrite() anyway.
+    Optional<size_t> beforeTryWrite();
+
+    // To be called after trying to write a new fixed-size message (which should
+    // happen after beforeWrite() or beforeTryWrite()).
+    // |success| must be true to indicate that a new item was added to the
+    // channel, or false otherwise (i.e. if the channel is stopped, or if
+    // beforeTryWrite() returned an empty optional).
+    void afterWrite(bool success);
+
+    // Call this method in the receiver thread before reading a new message.
+    // This returns the position in the message array where the new message
+    // can be read. Caller must process the message, then call afterRead().
+    // If the channel is stopped, return value is undefined.
+    size_t beforeRead();
+
+    // Same as beforeRead(), but returns an empty optional if there was
+    // no data to read instead of waiting for it.
+    // One still needs to call afterWrite() anyway.
+    Optional<size_t> beforeTryRead();
+
+    // Same as beforeRead(), but returns an empty optional if no data arrived
+    // by the |wallTimeUs| absolute time. One still needs to call
+    // afterWrite() anyway.
+    Optional<size_t> beforeTimedRead(uint64_t wallTimeUs);
+
+    // To be called after reading a fixed-size message from the channel (which
+    // must happen after beforeRead() or beforeTryRead()).
+    // |success| must be true to indicate that a message was read, or false
+    // otherwise (i.e. if the channel is stopped or if beforeTryRead() returned
+    // an empty optional).
+    void afterRead(bool success);
+
+    // A version of isStopped() that doesn't lock the channel but expects it
+    // to be locked by the caller.
+    bool isStoppedLocked() const { return mStopped; }
+
+private:
+    size_t mPos = 0;
+    size_t mCapacity;
+    size_t mCount = 0;
+    bool mStopped = false;
+    mutable Lock mLock;     // Mutable to allow const members to lock it.
+    ConditionVariable mCanRead;
+    ConditionVariable mCanWrite;
+};
+
+// Helper class used to implement an uni-directional IPC channel between
+// two threads. The channel can be used to send fixed-size messages of type
+// |T|, with an internal buffer size of |CAPACITY| items. All calls are
+// blocking.
+//
+// Usage is pretty straightforward:
+//
+//   - From the sender thread, call send(msg);
+//   - From the receiver thread, call receive(&msg);
+//   - If you want to stop the IPC, call stop();
+template <typename T, size_t CAPACITY>
+class MessageChannel : public MessageChannelBase {
+public:
+    MessageChannel() : MessageChannelBase(CAPACITY) {}
+
+    bool send(const T& msg) {
+        const size_t pos = beforeWrite();
+        const bool res = !isStoppedLocked();
+        if (res) {
+            mItems[pos] = msg;
+        }
+        afterWrite(res);
+        return res;
+    }
+
+    bool send(T&& msg) {
+        const size_t pos = beforeWrite();
+        const bool res = !isStoppedLocked();
+        if (res) {
+            mItems[pos] = std::move(msg);
+        }
+        afterWrite(res);
+        return res;
+    }
+
+    bool trySend(const T& msg) {
+        const auto pos = beforeTryWrite();
+        if (pos) {
+            mItems[*pos] = msg;
+        }
+        afterWrite(pos);
+        return pos;
+    }
+
+    bool trySend(T&& msg) {
+        const auto pos = beforeTryWrite();
+        if (pos) {
+            mItems[*pos] = std::move(msg);
+        }
+        afterWrite(pos);
+        return pos;
+    }
+
+    bool receive(T* msg) {
+        const size_t pos = beforeRead();
+        const bool res = !isStoppedLocked();
+        if (res) {
+            *msg = std::move(mItems[pos]);
+        }
+        afterRead(res);
+        return res;
+    }
+
+    Optional<T> receive() {
+        const size_t pos = beforeRead();
+        if (!isStoppedLocked()) {
+            Optional<T> msg(std::move(mItems[pos]));
+            afterRead(true);
+            return msg;
+        } else {
+            afterRead(false);
+            return {};
+        }
+    }
+
+    bool tryReceive(T* msg) {
+        const auto pos = beforeTryRead();
+        if (pos) {
+            *msg = std::move(mItems[*pos]);
+        }
+        afterRead(pos);
+        return pos;
+    }
+
+    Optional<T> timedReceive(uint64_t wallTimeUs) {
+        const auto pos = beforeTimedRead(wallTimeUs);
+        if (pos && !isStoppedLocked()) {
+            Optional<T> res(std::move(mItems[*pos]));
+            afterRead(true);
+            return res;
+        }
+        afterRead(false);
+        return {};
+    }
+
+    constexpr size_t capacity() const { return CAPACITY; }
+
+private:
+    T mItems[CAPACITY];
+};
+
+}  // namespace base
+}  // namespace android
diff --git a/base/PathUtils.cpp b/base/PathUtils.cpp
new file mode 100644
index 0000000..50e09b3
--- /dev/null
+++ b/base/PathUtils.cpp
@@ -0,0 +1,340 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "base/PathUtils.h"
+
+#include <string.h>                      // for size_t, strncmp
+#include <iterator>                      // for reverse_iterator, operator!=
+#include <numeric>                       // for accumulate
+#include <type_traits>                   // for enable_if<>::type
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#include "Win32UnicodeString.h"
+#endif
+
+static inline bool sIsEmpty(const char* str) {
+    return !str || str[0] == '\0';
+}
+
+namespace android {
+namespace base {
+
+const char* const PathUtils::kExeNameSuffixes[kHostTypeCount] = {"", ".exe"};
+
+const char* const PathUtils::kExeNameSuffix =
+        PathUtils::kExeNameSuffixes[PathUtils::HOST_TYPE];
+
+std::string PathUtils::toExecutableName(const char* baseName,
+                                        HostType hostType) {
+    return static_cast<std::string>(baseName).append(
+            kExeNameSuffixes[hostType]);
+}
+
+// static
+bool PathUtils::isDirSeparator(int ch, HostType hostType) {
+    return (ch == '/') || (hostType == HOST_WIN32 && ch == '\\');
+}
+
+// static
+bool PathUtils::isPathSeparator(int ch, HostType hostType) {
+    return (hostType == HOST_POSIX && ch == ':') ||
+           (hostType == HOST_WIN32 && ch == ';');
+}
+
+// static
+size_t PathUtils::rootPrefixSize(const std::string& path, HostType hostType) {
+    if (path.empty()) return 0;
+
+    if (hostType != HOST_WIN32)
+        return (path[0] == '/') ? 1U : 0U;
+
+    size_t result = 0;
+    if (path[1] == ':') {
+        int ch = path[0];
+        if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
+            result = 2U;
+    } else if (!strncmp(path.c_str(), "\\\\.\\", 4) ||
+               !strncmp(path.c_str(), "\\\\?\\", 4)) {
+        // UNC prefixes.
+        return 4U;
+    } else if (isDirSeparator(path[0], hostType)) {
+        result = 1;
+        if (isDirSeparator(path[1], hostType)) {
+            result = 2;
+            while (path[result] && !isDirSeparator(path[result], HOST_WIN32))
+                result++;
+        }
+    }
+    if (result && path[result] && isDirSeparator(path[result], HOST_WIN32))
+        result++;
+
+    return result;
+}
+
+// static
+bool PathUtils::isAbsolute(const char* path, HostType hostType) {
+    size_t prefixSize = rootPrefixSize(path, hostType);
+    if (!prefixSize) {
+        return false;
+    }
+    if (hostType != HOST_WIN32) {
+        return true;
+    }
+    return isDirSeparator(path[prefixSize - 1], HOST_WIN32);
+}
+
+// static
+std::string PathUtils::removeTrailingDirSeparator(const char* path,
+                                                 HostType hostType) {
+    size_t pathLen = strlen(path);
+    // NOTE: Don't remove initial path separator for absolute paths.
+    while (pathLen > 1U && isDirSeparator(path[pathLen - 1U], hostType)) {
+        pathLen--;
+    }
+    return std::string(path, pathLen);
+}
+
+// static
+std::string PathUtils::addTrailingDirSeparator(const char* path,
+                                               HostType hostType) {
+    std::string result = path;
+    if (result.size() > 0 && !isDirSeparator(result[result.size() - 1U])) {
+        result += getDirSeparator(hostType);
+    }
+    return result;
+}
+
+// static
+bool PathUtils::split(const char* path,
+                      HostType hostType,
+                      const char** dirName,
+                      const char** baseName) {
+    if (sIsEmpty(path)) {
+        return false;
+    }
+
+    // If there is a trailing directory separator, return an error.
+    size_t end = strlen(path);
+    if (isDirSeparator(path[end - 1U], hostType)) {
+        return false;
+    }
+
+    // Find last separator.
+    size_t prefixLen = rootPrefixSize(path, hostType);
+    size_t pos = end;
+    while (pos > prefixLen && !isDirSeparator(path[pos - 1U], hostType)) {
+        pos--;
+    }
+
+    // Handle common case.
+    if (pos > prefixLen) {
+        if (dirName) {
+            *dirName = path;
+        }
+        if (baseName) {
+            *baseName = path + pos;
+        }
+        return true;
+    }
+
+    // If there is no directory separator, the path is a single file name.
+    if (dirName) {
+        if (!prefixLen) {
+            *dirName = ".";
+        } else {
+            *dirName = path;
+        }
+    }
+    if (baseName) {
+        *baseName = path + prefixLen;
+    }
+    return true;
+}
+
+// static
+std::string PathUtils::join(const std::string& path1,
+                            const std::string& path2,
+                            HostType hostType) {
+    if (path1.empty()) {
+        return path2;
+    }
+    if (path2.empty()) {
+        return path1;
+    }
+    if (isAbsolute(path2.c_str(), hostType)) {
+        return path2;
+    }
+    size_t prefixLen = rootPrefixSize(path1, hostType);
+    std::string result(path1);
+    size_t end = result.size();
+    if (end > prefixLen && !isDirSeparator(result[end - 1U], hostType)) {
+        result += getDirSeparator(hostType);
+    }
+    result += path2;
+    return result;
+}
+
+// static
+template <class String>
+std::vector<String> PathUtils::decompose(const String& path,
+                                         HostType hostType) {
+    std::vector<String> result;
+    if (path.empty())
+        return result;
+
+    size_t prefixLen = rootPrefixSize(path, hostType);
+    auto it = path.begin();
+    if (prefixLen) {
+        result.emplace_back(it, it + prefixLen);
+        it += prefixLen;
+    }
+    for (;;) {
+        auto p = it;
+        while (*p && !isDirSeparator(*p, hostType))
+            p++;
+        if (p > it) {
+            result.emplace_back(it, p);
+        }
+        if (!*p) {
+            break;
+        }
+        it = p + 1;
+    }
+    return result;
+}
+
+std::vector<std::string> PathUtils::decompose(std::string&& path,
+                                              HostType hostType) {
+    return decompose<std::string>(path, hostType);
+}
+
+template <class String>
+std::string PathUtils::recompose(const std::vector<String>& components,
+                                 HostType hostType) {
+    if (components.empty()) {
+        return {};
+    }
+
+    const char dirSeparator = getDirSeparator(hostType);
+    std::string result;
+    // To reduce memory allocations, compute capacity before doing the
+    // real append.
+    const size_t capacity =
+            components.size() - 1 +
+            std::accumulate(components.begin(), components.end(), size_t(0),
+                            [](size_t val, const String& next) {
+                                return val + next.size();
+                            });
+
+    result.reserve(capacity);
+    bool addSeparator = false;
+    for (size_t n = 0; n < components.size(); ++n) {
+        const auto& component = components[n];
+        if (addSeparator)
+            result += dirSeparator;
+        addSeparator = true;
+        if (n == 0) {
+            size_t prefixLen = rootPrefixSize(component, hostType);
+            if (prefixLen == component.size()) {
+                addSeparator = false;
+            }
+        }
+        result += component;
+    }
+    return result;
+}
+
+// static
+std::string PathUtils::recompose(const std::vector<std::string>& components,
+                                 HostType hostType) {
+    return recompose<std::string>(components, hostType);
+}
+
+// static
+template <class String>
+void PathUtils::simplifyComponents(std::vector<String>* components) {
+    std::vector<String> stack;
+    for (auto& component : *components) {
+        if (component == ".") {
+            // Ignore any instance of '.' from the list.
+            continue;
+        }
+        if (component == "..") {
+            // Handling of '..' is specific: if there is a item on the
+            // stack that is not '..', then remove it, otherwise push
+            // the '..'.
+            if (!stack.empty() && stack.back() != "..") {
+                stack.pop_back();
+            } else {
+                stack.push_back(std::move(component));
+            }
+            continue;
+        }
+        // If not a '..', just push on the stack.
+        stack.push_back(std::move(component));
+    }
+    if (stack.empty()) {
+        stack.push_back(".");
+    }
+    components->swap(stack);
+}
+
+void PathUtils::simplifyComponents(std::vector<std::string>* components) {
+    simplifyComponents<std::string>(components);
+}
+
+#ifdef _WIN32
+
+// Return |path| as a Unicode string, while discarding trailing separators.
+Win32UnicodeString win32Path(const char* path) {
+    Win32UnicodeString wpath(path);
+    // Get rid of trailing directory separators, Windows doesn't like them.
+    size_t size = wpath.size();
+    while (size > 0U &&
+           (wpath[size - 1U] == L'\\' || wpath[size - 1U] == L'/')) {
+        size--;
+    }
+    if (size < wpath.size()) {
+        wpath.resize(size);
+    }
+    return wpath;
+}
+
+static int GetWin32Mode(int mode) {
+    // Convert |mode| to win32 permission bits.
+    int win32mode = 0x0;
+
+    if ((mode & R_OK) || (mode & X_OK)) {
+        win32mode |= 0x4;
+    }
+    if (mode & W_OK) {
+        win32mode |= 0x2;
+    }
+
+    return win32mode;
+}
+
+#endif
+
+bool pathExists(const char* path) {
+#ifdef _WIN32
+    return _waccess(win32Path(path).c_str(), GetWin32Mode(F_OK));
+#else
+    return 0 == access(path, F_OK);
+#endif
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/PathUtils.h b/base/PathUtils.h
new file mode 100644
index 0000000..1ec3f40
--- /dev/null
+++ b/base/PathUtils.h
@@ -0,0 +1,297 @@
+// Copyright 2020 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 <stddef.h>                   // for size_t
+#include <string>                     // for string, basic_string
+#include <utility>                    // for move, forward
+#include <vector>                     // for vector
+
+#include "base/Optional.h"    // for Optional
+
+#ifdef __APPLE__
+
+#define LIBSUFFIX ".dylib"
+
+#else
+
+#ifdef _WIN32
+#include "base/Win32UnicodeString.h"
+#define LIBSUFFIX ".dll"
+
+#else
+
+#define LIBSUFFIX ".so"
+
+#endif // !_WIN32 (linux)
+
+#endif // !__APPLE__
+
+namespace android {
+namespace base {
+
+// Utility functions to manage file paths. None of these should touch the
+// file system. All methods must be static.
+class PathUtils {
+public:
+    // An enum listing the supported host file system types.
+    // HOST_POSIX means a Posix-like file system.
+    // HOST_WIN32 means a Windows-like file system.
+    // HOST_TYPE means the current host type (one of the above).
+    // NOTE: If you update this list, modify kHostTypeCount below too.
+    enum HostType {
+        HOST_POSIX = 0,
+        HOST_WIN32 = 1,
+#ifdef _WIN32
+        HOST_TYPE = HOST_WIN32,
+#else
+        HOST_TYPE = HOST_POSIX,
+#endif
+    };
+
+    // The number of distinct items in the HostType enumeration above.
+    static const int kHostTypeCount = 2;
+
+    // Suffixes for an executable file (.exe on Windows, empty otherwise)
+    static const char* const kExeNameSuffixes[kHostTypeCount];
+
+    // Suffixe for an executable file on the current platform
+    static const char* const kExeNameSuffix;
+
+    // Returns the executable name for a base name |baseName|
+    static std::string toExecutableName(const char* baseName, HostType hostType);
+
+    static std::string toExecutableName(const char* baseName) {
+        return toExecutableName(baseName, HOST_TYPE);
+    }
+
+    // Return true if |ch| is a directory separator for a given |hostType|.
+    static bool isDirSeparator(int ch, HostType hostType);
+
+    // Return true if |ch| is a directory separator for the current platform.
+    static bool isDirSeparator(int ch) {
+        return isDirSeparator(ch, HOST_TYPE);
+    }
+
+    // Return true if |ch| is a path separator for a given |hostType|.
+    static bool isPathSeparator(int ch, HostType hostType);
+
+    // Return true if |ch| is a path separator for the current platform.
+    static bool isPathSeparator(int ch) {
+        return isPathSeparator(ch, HOST_TYPE);
+    }
+
+    // Return the directory separator character for a given |hostType|
+    static char getDirSeparator(HostType hostType) {
+        return (hostType == HOST_WIN32) ? '\\' : '/';
+    }
+
+    // Remove trailing separators from a |path| string, for a given |hostType|.
+    static std::string  removeTrailingDirSeparator(const char* path,
+                                                 HostType hostType);
+
+    // Remove trailing separators from a |path| string for the current host.
+    static std::string removeTrailingDirSeparator(const char* path) {
+        return removeTrailingDirSeparator(path, HOST_TYPE);
+    }
+
+    // Add a trailing separator if needed.
+    static std::string addTrailingDirSeparator(const char* path,
+                                               HostType hostType);
+
+    // Add a trailing separator if needed.
+    static std::string addTrailingDirSeparator(const char* path) {
+        return addTrailingDirSeparator(path, HOST_TYPE);
+    }
+
+    // If |path| starts with a root prefix, return its size in bytes, or
+    // 0 otherwise. The definition of valid root prefixes depends on the
+    // value of |hostType|. For HOST_POSIX, it's any path that begins
+    // with a slash (/). For HOST_WIN32, the following prefixes are
+    // recognized:
+    //    <drive>:
+    //    <drive>:<sep>
+    //    <sep><sep>volumeName<sep>
+    static size_t rootPrefixSize(const std::string& path, HostType hostType);
+
+    // Return the root prefix for the current platform. See above for
+    // documentation.
+    static size_t rootPrefixSize(const char* path) {
+        return rootPrefixSize(path, HOST_TYPE);
+    }
+
+    // Return true iff |path| is an absolute path for a given |hostType|.
+    static bool isAbsolute(const char* path, HostType hostType);
+
+    // Return true iff |path| is an absolute path for the current host.
+    static bool isAbsolute(const char* path) {
+        return isAbsolute(path, HOST_TYPE);
+    }
+
+    // Split |path| into a directory name and a file name. |dirName| and
+    // |baseName| are optional pointers to strings that will receive the
+    // corresponding components on success. |hostType| is a host type.
+    // Return true on success, or false on failure.
+    // Note that unlike the Unix 'basename' command, the command will fail
+    // if |path| ends with directory separator or is a single root prefix.
+    // Windows root prefixes are fully supported, which means the following:
+    //
+    //     /            -> error.
+    //     /foo         -> '/' + 'foo'
+    //     foo          -> '.' + 'foo'
+    //     <drive>:     -> error.
+    //     <drive>:foo  -> '<drive>:' + 'foo'
+    //     <drive>:\foo -> '<drive>:\' + 'foo'
+    //
+    static bool split(const char* path,
+                      HostType hostType,
+                      const char** dirName,
+                      const char** baseName);
+
+    // A variant of split() for the current process' host type.
+    static bool split(const char* path,
+                      const char** dirName,
+                      const char** baseName) {
+        return split(path, HOST_TYPE, dirName, baseName);
+    }
+
+    // Join two path components together. Note that if |path2| is an
+    // absolute path, this function returns a copy of |path2|, otherwise
+    // the result will be the concatenation of |path1| and |path2|, if
+    // |path1| doesn't end with a directory separator, a |hostType| specific
+    // one will be inserted between the two paths in the result.
+    static std::string join(const std::string& path1,
+                            const std::string& path2,
+                            HostType hostType);
+
+    // A variant of join() for the current process' host type.
+    static std::string join(const std::string& path1, const std::string& path2) {
+        return join(path1, path2, HOST_TYPE);
+    }
+
+    // A convenience function to join a bunch of paths at once
+    template <class... Paths>
+    static std::string join(const std::string& path1,
+                            const std::string& path2,
+                            Paths&&... paths) {
+        return join(path1, join(path2, std::forward<Paths>(paths)...));
+    }
+
+    // Decompose |path| into individual components. If |path| has a root
+    // prefix, it will always be the first component. I.e. for Posix
+    // systems this will be '/' (for absolute paths). For Win32 systems,
+    // it could be 'C:" (for a path relative to a root volume) or "C:\"
+    // for an absolute path from volume C).,
+    // On success, return true and sets |out| to a vector of strings,
+    // each one being a path component (prefix or subdirectory or file
+    // name). Directory separators do not appear in components, except
+    // for the root prefix, if any.
+    static std::vector<std::string> decompose(std::string&& path,
+                                              HostType hostType);
+
+    template <class String>
+    static std::vector<String> decompose(const String& path,
+                                         HostType hostType);
+
+    // Decompose |path| into individual components for the host platform.
+    // See comments above for more details.
+    static std::vector<std::string> decompose(std::string&& path) {
+        return decompose(std::move(path), HOST_TYPE);
+    }
+
+    // Recompose a path from individual components into a file path string.
+    // |components| is a vector of strings, and |hostType| the target
+    // host type to use. Return a new file path string. Note that if the
+    // first component is a root prefix, it will be kept as is, i.e.:
+    //   [ 'C:', 'foo' ] -> 'C:foo' on Win32, but not Posix where it will
+    // be 'C:/foo'.
+    static std::string recompose(const std::vector<std::string>& components,
+                                 HostType hostType);
+    template <class String>
+    static std::string recompose(const std::vector<String>& components,
+                                 HostType hostType);
+
+    // Recompose a path from individual components into a file path string
+    // for the current host. |components| is a vector os strings.
+    // Returns a new file path string.
+    template <class String>
+    static std::string recompose(const std::vector<String>& components) {
+        return PathUtils::recompose(components, HOST_TYPE);
+    }
+
+    // Given a list of components returned by decompose(), simplify it
+    // by removing instances of '.' and '..' when that makes sense.
+    // Note that it is not possible to simplify initial instances of
+    // '..', i.e. "foo/../../bar" -> "../bar"
+    static void simplifyComponents(std::vector<std::string>* components);
+    template <class String>
+    static void simplifyComponents(std::vector<String>* components);
+
+    // Returns a version of |path| that is relative to |base|.
+    // This can be useful for converting absolute paths to
+    // relative paths given |base|.
+    // Example:
+    // |base|: C:\Users\foo
+    // |path|: C:\Users\foo\AppData\Local\Android\Sdk
+    // would give
+    // AppData\Local\Android\Sdk.
+    // If |base| is not a prefix of |path|, fails by returning
+    // the original |path| unmodified.
+    static std::string relativeTo(const char* base, const char* path, HostType hostType);
+    static std::string relativeTo(const char* base, const char* path) {
+        return relativeTo(base, path, HOST_TYPE);
+    }
+
+    static Optional<std::string> pathWithoutDirs(const char* name);
+    static Optional<std::string> pathToDir(const char* name);
+
+    // Replaces the entries ${xx} with the value of the environment variable
+    // xx if it exists. Returns kNullopt if the environment variable is
+    // not set or empty.
+    static Optional<std::string> pathWithEnvSubstituted(const char* path);
+
+    // Replaces the entries ${xx} with the value of the environment variable
+    // xx if it exists. Returns kNullopt if the environment variable is
+    // not set or empty.
+    static Optional<std::string> pathWithEnvSubstituted(std::vector<std::string> decomposedPath);
+
+#ifdef _WIN32
+    static Win32UnicodeString asUnicodePath(const char* path) { return Win32UnicodeString(path); }
+#else
+    static std::string asUnicodePath(const char* path) { return path; }
+#endif
+};
+
+// Useful shortcuts to avoid too much typing.
+static const PathUtils::HostType kHostPosix = PathUtils::HOST_POSIX;
+static const PathUtils::HostType kHostWin32 = PathUtils::HOST_WIN32;
+static const PathUtils::HostType kHostType = PathUtils::HOST_TYPE;
+
+template <class... Paths>
+std::string pj(const std::string& path1,
+                  const std::string& path2,
+                  Paths&&... paths) {
+    return PathUtils::join(path1,
+               pj(path2, std::forward<Paths>(paths)...));
+}
+
+std::string pj(const std::string& path1, const std::string& path2);
+
+std::string pj(const std::vector<std::string>& paths);
+
+bool pathExists(const char* path);
+
+}  // namespace base
+}  // namespace android
diff --git a/base/SharedLibrary.cpp b/base/SharedLibrary.cpp
new file mode 100644
index 0000000..59db81c
--- /dev/null
+++ b/base/SharedLibrary.cpp
@@ -0,0 +1,295 @@
+// Copyright (C) 2014 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 "base/SharedLibrary.h"
+#include "base/PathUtils.h"
+
+#include <functional>
+#include <vector>
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef _WIN32
+#include <dlfcn.h>
+#include <stdlib.h>
+#endif
+
+#define GL_LOG(...)
+
+using android::base::PathUtils;
+
+namespace android {
+namespace base {
+
+class LibrarySearchPaths {
+public:
+    LibrarySearchPaths() = default;
+
+    void addPath(const char* path) {
+        mPaths.push_back(path);
+    }
+
+    void forEachPath(std::function<void(const std::string&)> func) {
+        for (const auto& path: mPaths) {
+            func(path);
+        }
+    }
+
+private:
+    std::vector<std::string> mPaths;
+};
+
+LibrarySearchPaths* sSearchPaths() {
+    static LibrarySearchPaths* paths = new LibrarySearchPaths;
+    return paths;
+}
+
+SharedLibrary::LibraryMap SharedLibrary::s_libraryMap = LibraryMap();
+
+// static
+SharedLibrary* SharedLibrary::open(const char* libraryName) {
+    GL_LOG("SharedLibrary::open for [%s]\n", libraryName);
+    char error[1];
+    return open(libraryName, error, sizeof(error));
+}
+
+SharedLibrary* SharedLibrary::open(const char* libraryName,
+                                   char* error,
+                                   size_t errorSize) {
+    auto lib = s_libraryMap.find(libraryName);
+
+    if (lib == s_libraryMap.end()) {
+        GL_LOG("SharedLibrary::open for [%s]: not found in map, open for the first time\n", libraryName);
+        SharedLibrary* load = do_open(libraryName, error, errorSize);
+        if (load != nullptr) {
+            s_libraryMap[libraryName] = std::move(
+                    std::unique_ptr<SharedLibrary, SharedLibrary::Deleter>(
+                            load));
+        }
+        return load;
+    }
+
+    return lib->second.get();
+}
+
+#ifdef _WIN32
+
+// static
+SharedLibrary* SharedLibrary::do_open(const char* libraryName,
+                                   char* error,
+                                   size_t errorSize) {
+    GL_LOG("SharedLibrary::open for [%s] (win32): call LoadLibrary\n", libraryName);
+    HMODULE lib = LoadLibrary(libraryName);
+
+    // Try a bit harder to find the shared library if we cannot find it.
+    if (!lib) {
+        GL_LOG("SharedLibrary::open for [%s] can't find in default path. Searching alternatives...\n",
+               libraryName);
+        sSearchPaths()->forEachPath([&lib, libraryName](const std::string& path) {
+            if (!lib) {
+                auto libName = PathUtils::join(path, libraryName);
+                GL_LOG("SharedLibrary::open for [%s]: trying [%s]\n",
+                       libraryName, libName.c_str());
+                lib = LoadLibrary(libName.c_str());
+                GL_LOG("SharedLibrary::open for [%s]: trying [%s]. found? %d\n",
+                       libraryName, libName.c_str(), lib != nullptr);
+            }
+        });
+    }
+
+    if (lib) {
+        constexpr size_t kMaxPathLength = 2048;
+        char fullPath[kMaxPathLength];
+        GetModuleFileNameA(lib, fullPath, kMaxPathLength);
+        GL_LOG("SharedLibrary::open succeeded for [%s]. File name: [%s]\n",
+               libraryName, fullPath);
+        return new SharedLibrary(lib);
+    }
+
+    if (errorSize == 0) {
+        GL_LOG("SharedLibrary::open for [%s] failed, but no error\n",
+               libraryName);
+        return NULL;
+    }
+
+    // Convert error into human-readable message.
+    DWORD errorCode = ::GetLastError();
+    LPSTR message = NULL;
+    size_t messageLen = FormatMessageA(
+            FORMAT_MESSAGE_ALLOCATE_BUFFER |
+            FORMAT_MESSAGE_FROM_SYSTEM |
+            FORMAT_MESSAGE_IGNORE_INSERTS,
+            NULL,
+            errorCode,
+            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+            (LPSTR) &message,
+            0,
+            NULL);
+
+    int ret = snprintf(error, errorSize, "%.*s", (int)messageLen, message);
+    if (ret < 0 || ret == static_cast<int>(errorSize)) {
+        // snprintf() on Windows doesn't behave as expected by C99,
+        // this path is to ensure that the result is always properly
+        // zero-terminated.
+        ret = static_cast<int>(errorSize - 1);
+        error[ret] = '\0';
+    }
+    // Remove any trailing \r\n added by FormatMessage
+    if (ret > 0 && error[ret - 1] == '\n') {
+        error[--ret] = '\0';
+    }
+    if (ret > 0 && error[ret - 1] == '\r') {
+        error[--ret] = '\0';
+    }
+    GL_LOG("Failed to load [%s]. Error string: [%s]\n",
+           libraryName, error);
+
+    return NULL;
+}
+
+SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {}
+
+SharedLibrary::~SharedLibrary() {
+    if (mLib) {
+        // BUG: 66013149
+        // In windows it sometimes hang on exit when destroying s_libraryMap.
+        // Let's skip freeing the library, since pretty much the only situation
+        // we need to do it, is on exit.
+        //FreeLibrary(mLib);
+    }
+}
+
+SharedLibrary::FunctionPtr SharedLibrary::findSymbol(
+        const char* symbolName) const {
+    if (!mLib || !symbolName) {
+        return NULL;
+    }
+    return reinterpret_cast<FunctionPtr>(
+                GetProcAddress(mLib, symbolName));
+}
+
+#else // !_WIN32
+
+// static
+SharedLibrary* SharedLibrary::do_open(const char* libraryName,
+                                   char* error,
+                                   size_t errorSize) {
+    GL_LOG("SharedLibrary::open for [%s] (posix): begin\n", libraryName);
+
+    const char* libPath = libraryName;
+    char* path = NULL;
+
+    const char* libBaseName = strrchr(libraryName, '/');
+    if (!libBaseName) {
+        libBaseName = libraryName;
+    }
+
+    if (!strchr(libBaseName, '.')) {
+        // There is no extension in this library name, so append one.
+#ifdef __APPLE__
+        static const char kDllExtension[] = ".dylib";
+#else
+        static const char kDllExtension[] = ".so";
+#endif
+        size_t pathLen = strlen(libraryName) + sizeof(kDllExtension);
+        path = static_cast<char*>(malloc(pathLen));
+        snprintf(path, pathLen, "%s%s", libraryName, kDllExtension);
+        libPath = path;
+    }
+
+    dlerror();  // clear error.
+
+#ifdef __APPLE__
+    // On OSX, some libraries don't include an extension (notably OpenGL)
+    // On OSX we try to open |libraryName| first.  If that doesn't exist,
+    // we try |libraryName|.dylib
+    GL_LOG("SharedLibrary::open for [%s] (posix,darwin): call dlopen\n", libraryName);
+    void* lib = dlopen(libraryName, RTLD_NOW);
+    if (lib == NULL) {
+        GL_LOG("SharedLibrary::open for [%s] (posix,darwin): failed, "
+               "try again with [%s]\n", libraryName, libPath);
+        lib = dlopen(libPath, RTLD_NOW);
+
+        sSearchPaths()->forEachPath([&lib, libraryName, libPath](const std::string& path) {
+            if (!lib) {
+                auto libName = PathUtils::join(path, libraryName);
+                GL_LOG("SharedLibrary::open for [%s] (posix,darwin): still failed, "
+                       "try [%s]\n", libraryName, libName.c_str());
+                lib = dlopen(libName.c_str(), RTLD_NOW);
+                if (!lib) {
+                    auto libPathName = PathUtils::join(path, libPath);
+                    GL_LOG("SharedLibrary::open for [%s] (posix,darwin): still failed, "
+                           "try [%s]\n", libraryName, libPathName.c_str());
+                    lib = dlopen(libPathName.c_str(), RTLD_NOW);
+                }
+            }
+        });
+    }
+#else
+    GL_LOG("SharedLibrary::open for [%s] (posix,linux): call dlopen on [%s]\n",
+           libraryName, libPath);
+    void* lib = dlopen(libPath, RTLD_NOW);
+#endif
+
+    sSearchPaths()->forEachPath([&lib, libPath, libraryName](const std::string& path) {
+        if (!lib) {
+            auto libPathName = PathUtils::join(path, libPath);
+            GL_LOG("SharedLibrary::open for [%s] (posix): try again with %s\n",
+                   libraryName,
+                   libPathName.c_str());
+            lib = dlopen(libPathName.c_str(), RTLD_NOW);
+        }
+    });
+
+    if (path) {
+        free(path);
+    }
+
+    if (lib) {
+        return new SharedLibrary(lib);
+    }
+
+    snprintf(error, errorSize, "%s", dlerror());
+    GL_LOG("SharedLibrary::open for [%s] failed (posix). dlerror: [%s]\n",
+           libraryName, error);
+    return NULL;
+}
+
+SharedLibrary::SharedLibrary(HandleType lib) : mLib(lib) {}
+
+SharedLibrary::~SharedLibrary() {
+    if (mLib) {
+        dlclose(mLib);
+    }
+}
+
+SharedLibrary::FunctionPtr SharedLibrary::findSymbol(
+        const char* symbolName) const {
+    if (!mLib || !symbolName) {
+        return NULL;
+    }
+    return reinterpret_cast<FunctionPtr>(dlsym(mLib, symbolName));
+}
+
+#endif  // !_WIN32
+
+// static
+void SharedLibrary::addLibrarySearchPath(const char* path) {
+    sSearchPaths()->addPath(path);
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/SharedLibrary.h b/base/SharedLibrary.h
new file mode 100644
index 0000000..c9e5c8d
--- /dev/null
+++ b/base/SharedLibrary.h
@@ -0,0 +1,129 @@
+// Copyright (C) 2014 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 EMUGL_COMMON_SHARED_LIBRARY_H
+#define EMUGL_COMMON_SHARED_LIBRARY_H
+
+#include <stddef.h>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifdef _MSC_VER
+# ifdef BUILDING_EMUGL_COMMON_SHARED
+#  define EMUGL_COMMON_API __declspec(dllexport)
+# else
+#  define EMUGL_COMMON_API __declspec(dllimport)
+#endif
+#else
+# define EMUGL_COMMON_API
+#endif
+
+namespace android {
+namespace base {
+
+// A class used to open a platform-specific shared library, and probe
+// it for symbols. Usage is the following:
+//
+//    // Open the library.
+//    SharedLibrary* library = SharedLibrary::open("libFoo");
+//    if (!library) {
+//        ... could not find / open library!
+//    }
+//
+//    //Probe for function symbol.
+//    FunctionPtr my_func = library->findSymbol("my_func");
+//
+//  A shared library will be unloaded on program exit.
+class EMUGL_COMMON_API SharedLibrary {
+private:
+    struct Deleter {
+        void operator()(SharedLibrary* lib) const { delete lib; }
+    };
+
+public:
+    typedef std::unordered_map<
+            std::string,
+            std::unique_ptr<SharedLibrary, SharedLibrary::Deleter>>
+            LibraryMap;
+
+    // Open a given library.  If |libraryName| has no extension, a
+    // platform-appropriate extension is added and that path is opened.
+    // If the |libraryName| has an extension, that form is opened.
+    //
+    // On OSX, some libraries don't include an extension (notably OpenGL)
+    // On OSX we try to open |libraryName| first.  If that doesn't exist,
+    // we try |libraryName|.dylib
+    //
+    // On success, returns a new SharedLibrary instance that must be
+    // deleted by the caller.
+    static SharedLibrary* open(const char* libraryName);
+
+    // A variant of open() that can report a human-readable error if loading
+    // the library fails. |error| is a caller-provided buffer of |errorSize|
+    // bytes that will be filled with snprintf() and always zero terminated.
+    //
+    // On success, return a new SharedLibrary instance, and do not touch
+    // the content of |error|. On failure, return NULL, and sets the content
+    // of |error|.
+    static SharedLibrary* open(const char* libraryName,
+                               char* error,
+                               size_t errorSize);
+
+    // Adds an extra path to search for libraries.
+    static void addLibrarySearchPath(const char* path);
+
+    // Generic function pointer type, for values returned by the
+    // findSymbol() method.
+    typedef void (*FunctionPtr)(void);
+
+    // Probe a given SharedLibrary instance to find a symbol named
+    // |symbolName| in it. Return its address as a FunctionPtr, or
+    // NULL if the symbol is not found.
+    FunctionPtr findSymbol(const char* symbolName) const;
+
+private:
+
+    static LibraryMap s_libraryMap;
+
+    static SharedLibrary* do_open(const char* libraryName,
+                               char* error,
+                               size_t errorSize);
+#ifdef _WIN32
+    typedef HMODULE HandleType;
+#else
+    typedef void* HandleType;
+#endif
+
+    // Constructor intentionally hidden.
+    SharedLibrary(HandleType);
+
+    // Closes an existing SharedLibrary hidden so nobody
+    // starts accidently cleaning up these libraries.
+    ~SharedLibrary();
+
+
+    HandleType mLib;
+};
+
+#  define EMUGL_LIBNAME(name) "lib" name
+
+}  // namespace base
+}  // namespace android
+
+#endif  // EMUGL_COMMON_SHARED_LIBRARY_H
diff --git a/base/StaticMap.h b/base/StaticMap.h
new file mode 100644
index 0000000..a30127f
--- /dev/null
+++ b/base/StaticMap.h
@@ -0,0 +1,83 @@
+// 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.
+
+#include "base/Optional.h"
+#include "base/Lock.h"
+
+#include <functional>
+#include <unordered_map>
+
+namespace android {
+namespace base {
+
+// Static map class for use with LazyInstance or in global structures
+// as a process-wide registry of something. Safe for concurrent accress.
+template <class K, class V>
+class StaticMap {
+public:
+    StaticMap() = default;
+
+    void set(const K& key, const V& value) {
+        AutoLock lock(mLock);
+        mItems.emplace(key, value);
+    }
+
+    void erase(const K& key) {
+        AutoLock lock(mLock);
+        mItems.erase(key);
+    }
+
+    bool isPresent(const K& key) const {
+        AutoLock lock(mLock);
+        auto it = mItems.find(key);
+        return it != mItems.end();
+    }
+
+    android::base::Optional<V> get(const K& key) const {
+        AutoLock lock(mLock);
+        auto it = mItems.find(key);
+        if (it == mItems.end()) {
+            return android::base::kNullopt;
+        }
+        return it->second;
+    }
+
+    using ErasePredicate = std::function<bool(K, V)>;
+
+    void eraseIf(ErasePredicate p) {
+        AutoLock lock(mLock);
+        auto it = mItems.begin();
+        for (; it != mItems.end();) {
+            if (p(it->first, it->second)) {
+                it = mItems.erase(it);
+            } else {
+                ++it;
+            }
+        }
+    }
+
+    void clear() {
+        AutoLock lock(mLock);
+        mItems.clear();
+    }
+private:
+    using AutoLock = android::base::AutoLock;
+    using Lock = android::base::Lock;
+
+    mutable android::base::Lock mLock;
+    std::unordered_map<K, V> mItems;
+};
+
+} // namespace base
+} // namespace android
diff --git a/base/Stream.cpp b/base/Stream.cpp
index 5415059..6820d3b 100644
--- a/base/Stream.cpp
+++ b/base/Stream.cpp
@@ -103,17 +103,13 @@
     return u.f;
 }
 
-void Stream::putString(StringView str) {
-    this->putBe32(str.size());
-    this->write(str.data(), str.size());
-}
-
 void Stream::putString(const char* str) {
-    putString(StringView(str));
+    putString(str, strlen(str));
 }
 
 void Stream::putString(const char* str, size_t len) {
-    putString(StringView(str, len));
+    this->putBe32(len);
+    this->write(str, len);
 }
 
 std::string Stream::getString() {
diff --git a/base/Stream.h b/base/Stream.h
index 3451b91..8537d2c 100644
--- a/base/Stream.h
+++ b/base/Stream.h
@@ -14,8 +14,6 @@
 
 #pragma once
 
-#include "base/StringView.h"
-
 #include <string>
 
 #include <inttypes.h>
@@ -76,9 +74,6 @@
     // Read a single 32-bit float value from the stream.
     float getFloat();
 
-    // Write a string |str| into the stream. Ignore errors.
-    void putString(StringView str);
-
     // Write a 0-terminated C string |str| into the stream. Ignore error.
     void putString(const char* str);
 
diff --git a/base/StringView.h b/base/StringView.h
deleted file mode 100644
index 4d6a92e..0000000
--- a/base/StringView.h
+++ /dev/null
@@ -1,298 +0,0 @@
-// Copyright 2019 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 "base/Optional.h"
-#include "base/TypeTraits.h"
-
-#include <algorithm>
-#include <cstring>
-#include <string>
-
-namespace android {
-namespace base {
-
-// A StringView is a simple (address, size) pair that points to an
-// existing read-only string. It's a convenience class used to prevent
-// the creation of std::string() objects un-necessarily.
-//
-// Consider the two following functions:
-//
-//     size_t count1(const std::string& str) {
-//         size_t count = 0;
-//         for (size_t n = 0; n < str.size(); ++n) {
-//              if (str[n] == '1') {
-//                  count++;
-//              }
-//         }
-//         return count;
-//     }
-//
-//     size_t count2(const StringView& str) {
-//         size_t count = 0;
-//         for (size_t n = 0; n < str.size(); ++n) {
-//              if (str[n] == '2') {
-//                  count++;
-//              }
-//         }
-//         return count;
-//     }
-//
-// Then consider the following calls:
-//
-//       size_t n1 = count1("There is 1 one in this string!");
-//       size_t n2 = count2("I can count 2 too");
-//
-// In the first case, the compiler will silently create a temporary
-// std::string object, copy the input string into it (allocating memory in
-// the heap), call count1() and destroy the std::string upon its return.
-//
-// In the second case, the compiler will create a temporary StringView,
-// initialize it trivially before calling count2(), this results in
-// much less generated code, as well as better performance.
-//
-// Generally speaking, always use a reference or pointer to StringView
-// instead of a std::string if your function or method doesn't need to modify
-// its input.
-//
-class StringView {
-public:
-    constexpr StringView() : mString(""), mSize(0U) {}
-
-    constexpr StringView(const StringView& other) :
-        mString(other.data()), mSize(other.size()) {}
-
-    // IMPORTANT: all StringView constructors are intentionally not explict
-    // it is needed to allow seamless creation of StringView from all types
-    // of strings around - as it's intended to be a generic string wrapper
-
-    // A constexpr constructor from a constant buffer, initializing |mSize|
-    // as well. This allows one to declare a static const StringView instance
-    // and initialize it at compile time, with no runtime overhead:
-    //
-    // static constexpr StringView message = "blah";
-    //
-    template <size_t size>
-    constexpr StringView(const char (&buf)[size]) :
-        mString(buf), mSize(size - 1) {}
-
-    // Ctor for non-const arrays, AKA buffers. These usually contain some
-    // string formatted at runtime, so call strlen() instead of using the
-    // buffer size.
-    template <size_t size>
-    constexpr StringView(char (&buf)[size]) :
-        mString(buf), mSize(strlen(buf)) {}
-
-    // Constructor from a const char pointer. It has to be templated to make
-    // sure the array-based one is chosen for an array - otherwise non-templated
-    // overload always wins
-    // Note: the parameter type is a const reference to a const pointer. This
-    //   is to make this overload a poorer choice for the case of an array. For
-    //   the 'const char[]' argument both 'reference to an array' and 'pointer'
-    //   overloads are tied, so compiler can't choose without help
-    // Note2: for all constructors and set() calls, |end| must be
-    //   dereferencable. It is notrequired to be '\0', but there has to be some
-    //   data there. One may not construct a StringView passing past-the-end
-    //   iterator as |end|! StringView will try to dereference it.
-    template <class Char, class = enable_if<std::is_same<Char, char>>>
-    constexpr StringView(const Char* const & string) :
-            mString(string ? string : ""), mSize(string ? strlen(string) : 0) {}
-
-    StringView(const std::string& str) :
-        mString(str.c_str()), mSize(str.size()) {}
-
-    constexpr StringView(const char* str, size_t len)
-        : mString(str ? str : ""), mSize(len) {}
-
-    constexpr StringView(const char* begin, const char* end)
-        : mString(begin ? begin : ""), mSize(begin ? end - begin : 0) {}
-
-    constexpr StringView(std::nullptr_t) :
-            mString(""), mSize(0) {}
-
-    std::string str() const { return std::string(mString, mString + mSize); }
-    constexpr const char* data() const { return mString; }
-    constexpr size_t size() const { return mSize; }
-
-    typedef const char* iterator;
-    typedef const char* const_iterator;
-
-    constexpr const_iterator begin() const { return mString; }
-    constexpr const_iterator end() const { return mString + mSize; }
-
-    constexpr bool empty() const { return !size(); }
-    constexpr bool isNullTerminated() const { return *end() == '\0'; }
-
-    void clear() {
-        mSize = 0;
-        mString = "";
-    }
-
-    constexpr char operator[](size_t index) const {
-        return mString[index];
-    }
-
-    void set(const char* data, size_t len) {
-        mString = data ? data : "";
-        mSize = len;
-    }
-
-    void set(const char* str) {
-        mString = str ? str : "";
-        mSize = ::strlen(mString);
-    }
-
-    void set(const StringView& other) {
-        mString = other.mString;
-        mSize = other.mSize;
-    }
-
-    // Compare with another StringView.
-    int compare(const StringView& other) const;
-
-    StringView& operator=(const StringView& other) {
-        set(other);
-        return *this;
-    }
-
-    // find() first occurrence of |other| with an initial offset.
-    // Returns absolute offset (does not include |off|).
-    size_t find(StringView other, size_t off = 0) {
-        // Trivial case
-        if (!other.mSize) return 0;
-
-        size_t safeOff = std::min(off, mSize);
-
-        const char* searchStart = mString + safeOff;
-        const char* searchEnd = searchStart + mSize - safeOff;
-
-        const char* res =
-            std::search(searchStart, searchEnd,
-                        other.mString, other.mString + other.mSize);
-        if (res == searchEnd) return std::string::npos;
-        return (size_t)((uintptr_t)res - (uintptr_t)mString);
-    }
-
-    // getSubstr(); returns this string starting at the first place |other|
-    // occurs, otherwise a blank string.
-    StringView getSubstr(StringView other, size_t off = 0) {
-        size_t loc = find(other, off);
-        if (loc == std::string::npos) return StringView("");
-        return { mString + loc, end() };
-    }
-
-    // Returns substring starting at |begin| and running for |len|,
-    // or the rest of the string if |len| is std::string::npos.
-    StringView substr(size_t begin, size_t len = std::string::npos) {
-        if (len == std::string::npos) {
-            len = mSize - begin;
-        }
-        size_t safeOff = std::min(begin, mSize);
-        size_t safeLen = std::min(len, mSize - safeOff);
-        return { mString + safeOff, safeLen };
-    }
-
-    // Returns substring starting at |begin| ending at |end|,
-    // or the rest of the string if |end is std::string::npos.
-    StringView substrAbs(size_t begin, size_t end = std::string::npos) {
-        if (end == std::string::npos) {
-            end = begin + mSize;
-        }
-        return substr(begin, end - begin);
-    }
-
-    // Convert to std::string when needed.
-    operator std::string() const { return std::string(mString, mSize); }
-
-private:
-    const char* mString;
-    size_t mSize;
-};
-
-// Comparison operators. Defined as functions to allow automatic type
-// conversions with C strings and std::string objects.
-
-bool operator==(const StringView& x, const StringView& y);
-
-inline bool operator!=(const StringView& x, const StringView& y) {
-    return !(x == y);
-}
-
-inline bool operator<(const StringView& x, const StringView& y) {
-    return x.compare(y) < 0;
-}
-
-inline bool operator>=(const StringView& x, const StringView& y) {
-    return !(x < y);
-}
-
-inline bool operator >(const StringView& x, const StringView& y) {
-    return x.compare(y) > 0;
-}
-
-inline bool operator<=(const StringView& x, const StringView& y) {
-    return !(x > y);
-}
-
-// Helper to get a null-terminated const char* from a string view.
-// Only allocates if the StringView is not null terminated.
-//
-// Usage:
-//
-//      StringView myString = ...;
-//      printf("Contents: %s\n", c_str(myString));
-//
-// c_str(...) constructs a temporary object that may allocate memory if the
-// StringView is not null termianted.  The lifetime of the temporary object will
-// be until the next sequence point (typically the next semicolon).  If the
-// value needs to exist for longer than that, cache the instance.
-//
-//      StringView myString = ...;
-//      auto myNullTerminatedString = c_str(myString);
-//      functionAcceptingConstCharPointer(myNullTerminatedString);
-//
-class CStrWrapper {
-public:
-    CStrWrapper(StringView stringView) : mStringView(stringView) {}
-
-    // Returns a null-terminated char*, potentially creating a copy to add a
-    // null terminator.
-    const char* get() {
-        if (mStringView.isNullTerminated()) {
-            return mStringView.data();
-        } else {
-            // Create the std::string copy on-demand.
-            if (!mStringCopy) {
-                mStringCopy.emplace(mStringView.str());
-            }
-
-            return mStringCopy->c_str();
-        }
-    }
-
-    // Enable casting to const char*
-    operator const char*() { return get(); }
-
-private:
-    const StringView mStringView;
-    Optional<std::string> mStringCopy;
-};
-
-inline CStrWrapper c_str(StringView stringView) {
-    return CStrWrapper(stringView);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/base/System.cpp b/base/System.cpp
new file mode 100644
index 0000000..6306778
--- /dev/null
+++ b/base/System.cpp
@@ -0,0 +1,18 @@
+#include "base/System.h"
+
+namespace android {
+namespace base {
+
+std::string getEnvironmentVariable(const std::string& key) { 
+    return {};
+}
+
+void setEnvironmentVariable(const std::string& key) {
+}
+
+bool isVerboseLogging() {
+    return false;
+}
+
+} // namespace base
+} // namespace android
diff --git a/base/System.h b/base/System.h
new file mode 100644
index 0000000..aeed4c9
--- /dev/null
+++ b/base/System.h
@@ -0,0 +1,16 @@
+#include <string>
+
+namespace android {
+namespace base {
+
+std::string getEnvironmentVariable(const std::string& key);
+void setEnvironmentVariable(const std::string& key, const std::string& value);
+bool isVerboseLogging();
+
+uint64_t getUnixTimeUs();
+
+std::string getProgramDirectory();
+std::string getLauncherDirectory();
+
+} // namespace base
+} // namespace android
diff --git a/base/Tracing.cpp b/base/Tracing.cpp
new file mode 100644
index 0000000..fc9ac03
--- /dev/null
+++ b/base/Tracing.cpp
@@ -0,0 +1,85 @@
+// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// 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 "base/Tracing.h"
+
+#include <string>
+#include <vector>
+
+#include <fcntl.h>
+
+namespace android {
+namespace base {
+
+const bool* tracingDisabledPtr = nullptr;
+
+void initializeTracing() {
+    // virtualdeviceperfetto::initialize(&tracingDisabledPtr);
+}
+
+void enableTracing() {
+    // if (virtualdeviceperfetto::queryTraceConfig().tracingDisabled) {
+    //     virtualdeviceperfetto::enableTracing();
+    // }
+}
+
+void disableTracing() {
+    // if (!virtualdeviceperfetto::queryTraceConfig().tracingDisabled) {
+    //     virtualdeviceperfetto::disableTracing();
+    // }
+}
+
+bool shouldEnableTracing() {
+    // return !(virtualdeviceperfetto::queryTraceConfig().tracingDisabled);
+}
+
+#ifdef __cplusplus
+#   define CC_LIKELY( exp )    (__builtin_expect( !!(exp), true ))
+#   define CC_UNLIKELY( exp )  (__builtin_expect( !!(exp), false ))
+#else
+#   define CC_LIKELY( exp )    (__builtin_expect( !!(exp), 1 ))
+#   define CC_UNLIKELY( exp )  (__builtin_expect( !!(exp), 0 ))
+#endif
+
+__attribute__((always_inline)) void beginTrace(const char* name) {
+    if (CC_LIKELY(*tracingDisabledPtr)) return;
+    // virtualdeviceperfetto::beginTrace(name);
+}
+
+__attribute__((always_inline)) void endTrace() {
+    if (CC_LIKELY(*tracingDisabledPtr)) return;
+    // virtualdeviceperfetto::endTrace();
+}
+
+__attribute__((always_inline)) void traceCounter(const char* name, int64_t value) {
+    if (CC_LIKELY(*tracingDisabledPtr)) return;
+    // virtualdeviceperfetto::traceCounter(name, value);
+}
+
+ScopedTrace::ScopedTrace(const char* name) {
+    if (CC_LIKELY(*tracingDisabledPtr)) return;
+    // virtualdeviceperfetto::beginTrace(name);
+}
+
+ScopedTrace::~ScopedTrace() {
+    if (CC_LIKELY(*tracingDisabledPtr)) return;
+    // virtualdeviceperfetto::endTrace();
+}
+
+void setGuestTime(uint64_t t) {
+    // virtualdeviceperfetto::setGuestTime(t);
+}
+
+} // namespace base
+} // namespace android
diff --git a/base/Tracing.h b/base/Tracing.h
new file mode 100644
index 0000000..93557d0
--- /dev/null
+++ b/base/Tracing.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2019 Google Inc.
+//
+// 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 <inttypes.h>
+
+// Library to perform tracing. Talks to platform-specific
+// tracing libraries.
+namespace android {
+namespace base {
+
+// New tracing API that talks to an underlying tracing library, possibly perfetto.
+//
+// Sets up global state useful for tracing.
+void initializeTracing();
+
+// Enable/disable tracing
+void enableTracing();
+void disableTracing();
+
+// Set the time of traces on the host to be at this guest time.
+// Not needed if we assume timestamps can be transferrable (e.g.,
+// when RDTSC with raw passthrough is used)
+void setGuestTime(uint64_t guestTime);
+
+// Record a counter of some kind.
+void traceCounter(const char* tag, int64_t value);
+
+void beginTrace(const char* name);
+void endTrace();
+
+class ScopedTrace {
+public:
+    ScopedTrace(const char* name);
+    ~ScopedTrace();
+};
+
+class ScopedTraceDerived : public ScopedTrace {
+public:
+    void* member = nullptr;
+};
+
+void setGuestTime(uint64_t t);
+
+void enableTracing();
+void disableTracing();
+
+bool shouldEnableTracing();
+
+void traceCounter(const char* name, int64_t value);
+
+} // namespace base
+} // namespace android
+
+#define __AEMU_GENSYM2(x,y) x##y
+#define __AEMU_GENSYM1(x,y) __AEMU_GENSYM2(x,y)
+#define AEMU_GENSYM(x) __AEMU_GENSYM1(x,__COUNTER__)
+
+#define AEMU_SCOPED_TRACE(tag) __attribute__ ((unused)) android::base::ScopedTrace AEMU_GENSYM(aemuScopedTrace_)(tag)
+#define AEMU_SCOPED_TRACE_CALL() AEMU_SCOPED_TRACE(__func__)
+#define AEMU_SCOPED_THRESHOLD_TRACE_CALL()
+#define AEMU_SCOPED_THRESHOLD_TRACE(...)
diff --git a/base/Win32UnicodeString.cpp b/base/Win32UnicodeString.cpp
new file mode 100644
index 0000000..3658940
--- /dev/null
+++ b/base/Win32UnicodeString.cpp
@@ -0,0 +1,247 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "base/Win32UnicodeString.h"
+
+#include <algorithm>
+
+#include <windows.h>
+
+#include <string.h>
+
+namespace android {
+namespace base {
+
+Win32UnicodeString::Win32UnicodeString() : mStr(nullptr), mSize(0u) {}
+
+Win32UnicodeString::Win32UnicodeString(const char* str, size_t len)
+    : mStr(nullptr), mSize(0u) {
+    reset(str, strlen(str));
+}
+
+Win32UnicodeString::Win32UnicodeString(const char* str)
+    : mStr(nullptr), mSize(0u) {
+    reset(str);
+}
+
+Win32UnicodeString::Win32UnicodeString(size_t size) : mStr(nullptr), mSize(0u) {
+    resize(size);
+}
+
+Win32UnicodeString::Win32UnicodeString(const wchar_t* str)
+    : mStr(nullptr), mSize(0u) {
+    size_t len = str ? wcslen(str) : 0u;
+    resize(len);
+    ::memcpy(mStr, str ? str : L"", len * sizeof(wchar_t));
+}
+
+Win32UnicodeString::Win32UnicodeString(const Win32UnicodeString& other)
+    : mStr(nullptr), mSize(0u) {
+    resize(other.mSize);
+    ::memcpy(mStr, other.c_str(), other.mSize * sizeof(wchar_t));
+}
+
+Win32UnicodeString::~Win32UnicodeString() {
+    delete[] mStr;
+}
+
+Win32UnicodeString& Win32UnicodeString::operator=(
+        const Win32UnicodeString& other) {
+    resize(other.mSize);
+    ::memcpy(mStr, other.c_str(), other.mSize * sizeof(wchar_t));
+    return *this;
+}
+
+Win32UnicodeString& Win32UnicodeString::operator=(const wchar_t* str) {
+    size_t len = str ? wcslen(str) : 0u;
+    resize(len);
+    ::memcpy(mStr, str ? str : L"", len * sizeof(wchar_t));
+    return *this;
+}
+
+wchar_t* Win32UnicodeString::data() {
+    if (!mStr) {
+        // Ensure the function never returns NULL.
+        // it is safe to const_cast the pointer here - user isn't allowed to
+        // write into it anyway
+        return const_cast<wchar_t*>(L"");
+    }
+    return mStr;
+}
+
+std::string Win32UnicodeString::toString() const {
+    return convertToUtf8(mStr, mSize);
+}
+
+void Win32UnicodeString::reset(const char* str, size_t len) {
+    if (mStr) {
+        delete[] mStr;
+    }
+    const int utf16Len = calcUtf16BufferLength(str, len);
+    mStr = new wchar_t[utf16Len + 1];
+    mSize = static_cast<size_t>(utf16Len);
+    convertFromUtf8(mStr, utf16Len, str, len);
+    mStr[mSize] = L'\0';
+}
+
+void Win32UnicodeString::reset(const char* str) {
+    reset(str, strlen(str));
+}
+
+void Win32UnicodeString::resize(size_t newSize) {
+    if (newSize == 0) {
+        delete [] mStr;
+        mStr = nullptr;
+        mSize = 0;
+    } else if (newSize <= mSize) {
+        mStr[newSize] = 0;
+        mSize = newSize;
+    } else {
+        wchar_t* oldStr = mStr;
+        mStr = new wchar_t[newSize + 1u];
+        size_t copySize = std::min(newSize, mSize);
+        ::memcpy(mStr, oldStr ? oldStr : L"", copySize * sizeof(wchar_t));
+        mStr[copySize] = L'\0';
+        mStr[newSize] = L'\0';
+        mSize = newSize;
+        delete[] oldStr;
+    }
+}
+
+void Win32UnicodeString::append(const wchar_t* str) {
+    append(str, wcslen(str));
+}
+
+void Win32UnicodeString::append(const wchar_t* str, size_t len) {
+    // NOTE: This method should be rarely used, so don't try to optimize
+    // storage with larger capacity values and exponential increments.
+    if (!str || !len) {
+        return;
+    }
+    size_t oldSize = size();
+    resize(oldSize + len);
+    memmove(mStr + oldSize, str, len * sizeof(wchar_t));
+}
+
+void Win32UnicodeString::append(const Win32UnicodeString& other) {
+    append(other.c_str(), other.size());
+}
+
+wchar_t* Win32UnicodeString::release() {
+    wchar_t* result = mStr;
+    mStr = nullptr;
+    mSize = 0u;
+    return result;
+}
+
+// static
+std::string Win32UnicodeString::convertToUtf8(const wchar_t* str, int len) {
+    std::string result;
+    const int utf8Len = calcUtf8BufferLength(str, len);
+    if (utf8Len > 0) {
+        result.resize(static_cast<size_t>(utf8Len));
+        convertToUtf8(&result[0], utf8Len, str, len);
+        if (len == -1) {
+            result.resize(utf8Len - 1);  // get rid of the null-terminator
+        }
+    }
+    return result;
+}
+
+// returns the return value of a Win32UnicodeString public conversion function
+// from a WinAPI conversion function returned code
+static int convertRetVal(int winapiResult) {
+    return winapiResult ? winapiResult : -1;
+}
+
+// static
+int Win32UnicodeString::calcUtf8BufferLength(const wchar_t* str, int len) {
+    if (len < 0 && len != -1) {
+        return -1;
+    }
+    if (len == 0) {
+        return 0;
+    }
+    const int utf8Len = WideCharToMultiByte(CP_UTF8,  // CodePage
+                                            0,        // dwFlags
+                                            str,      // lpWideCharStr
+                                            len,      // cchWideChar
+                                            nullptr,  // lpMultiByteStr
+                                            0,        // cbMultiByte
+                                            nullptr,  // lpDefaultChar
+                                            nullptr); // lpUsedDefaultChar
+
+    return convertRetVal(utf8Len);
+}
+
+// static
+int Win32UnicodeString::calcUtf16BufferLength(const char* str, int len) {
+    if (len < 0 && len != -1) {
+        return -1;
+    }
+    if (len == 0) {
+        return 0;
+    }
+    const int utf16Len = MultiByteToWideChar(CP_UTF8,  // CodePage
+                                             0,        // dwFlags
+                                             str,      // lpMultiByteStr
+                                             len,      // cbMultiByte
+                                             nullptr,  // lpWideCharStr
+                                             0);       // cchWideChar
+
+    return convertRetVal(utf16Len);
+}
+
+// static
+int Win32UnicodeString::convertToUtf8(char* outStr, int outLen,
+                                      const wchar_t* str, int len) {
+    if (!outStr || outLen < 0 || !str || (len < 0 && len != -1)) {
+        return -1;
+    }
+    if (len == 0) {
+        return 0;
+    }
+
+    const int utf8Len = WideCharToMultiByte(CP_UTF8,  // CodePage
+                                            0,        // dwFlags
+                                            str,      // lpWideCharStr
+                                            len,      // cchWideChar
+                                            outStr,   // lpMultiByteStr
+                                            outLen,   // cbMultiByte
+                                            nullptr,  // lpDefaultChar
+                                            nullptr); // lpUsedDefaultChar
+    return convertRetVal(utf8Len);
+}
+
+// static
+int Win32UnicodeString::convertFromUtf8(wchar_t* outStr, int outLen,
+                                        const char* str, int len) {
+    if (!outStr || outLen < 0 || !str || (len < 0 && len != -1)) {
+        return -1;
+    }
+    if (len == 0) {
+        return 0;
+    }
+
+    const int utf16Len = MultiByteToWideChar(CP_UTF8,  // CodePage
+                                             0,        // dwFlags
+                                             str,      // lpMultiByteStr
+                                             len,      // cbMultiByte
+                                             outStr,   // lpWideCharStr
+                                             outLen);  // cchWideChar
+    return convertRetVal(utf16Len);
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/Win32UnicodeString.h b/base/Win32UnicodeString.h
new file mode 100644
index 0000000..58eda61
--- /dev/null
+++ b/base/Win32UnicodeString.h
@@ -0,0 +1,154 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#ifndef _WIN32
+// this file is just empty on non-Win32
+#else  // _WIN32
+
+#include "base/Compiler.h"
+
+#include <string>
+
+#include <wchar.h>
+
+namespace android {
+namespace base {
+
+// Helper class used to model a Windows Unicode string, which stores
+// text and file paths as a zero-terminated array of UTF-16 code points
+// (at least since Windows Vista, before that the encoding was slightly
+// different).
+//
+// This is very intentionally *not* a general purpose class. It should only
+// be used to simplify conversions between the Win32 Unicode API and the
+// rest of android::base which uses UTF-8 for all Unicode text.
+class Win32UnicodeString {
+public:
+    // Default constructor.
+    Win32UnicodeString();
+
+    // Initialize a new instance from UTF-8 text at |str| of |len| bytes.
+    // This doesn't try to validate the input, i.e. on error, the instance's
+    // content is undefined.
+    Win32UnicodeString(const char* str, size_t len);
+
+    // Initialize a new instance from an existing string instance |str|.
+    explicit Win32UnicodeString(const char* str);
+
+    // Initialize by reserving enough room for a string of |size| UTF-16
+    // codepoints.
+    explicit Win32UnicodeString(size_t size);
+
+    // Initialize from a zero-terminated wchar_t array.
+    explicit Win32UnicodeString(const wchar_t* str);
+
+    // Copy-constructor.
+    Win32UnicodeString(const Win32UnicodeString& other);
+
+    // Destructor.
+    ~Win32UnicodeString();
+
+    // Assignment operators.
+    Win32UnicodeString& operator=(const Win32UnicodeString& other);
+    Win32UnicodeString& operator=(const wchar_t* str);
+
+    // Return pointer to first wchar_t in the string.
+    const wchar_t* c_str() const { return mStr ? mStr : L""; }
+
+    // Return pointer to writable wchar_t array. This can never be NULL
+    // but no more than size() items should be accessed.
+    wchar_t* data();
+
+    // Return size of the string, this is the number of UTF-16 code points
+    // stored by the string, which may be larger than the number of actual
+    // Unicode characters in it.
+    size_t size() const { return mSize; }
+
+    // Convert to a string instance holding the corresponding UTF-8 text.
+    std::string toString() const;
+
+    // Return n-th character from string.
+    wchar_t operator[](size_t index) const { return mStr[index]; }
+
+    // Reset content from UTF-8 text at |str| or |len| bytes.
+    void reset(const char* str, size_t len);
+
+    // Reset content from UTF-8 text at |str|.
+    void reset(const char* str);
+
+    // Resize array.
+    void resize(size_t newSize);
+
+    // Append at the end of a Win32UnicodeString.
+    void append(const wchar_t* other);
+    void append(const wchar_t* other, size_t len);
+    void append(const Win32UnicodeString& other);
+
+    // Release the Unicode string array to the caller.
+    wchar_t* release();
+
+    // Directly convert a Unicode string to UTF-8 text and back.
+    // |len| - input length. if set to -1, means the input is null-terminated
+    static std::string convertToUtf8(const wchar_t* str, int len = -1);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Be careful when crossing this line. The following functions work with
+    // raw buffers of static length, and are much harder to use correctly.
+    // You've been warned
+    ////////////////////////////////////////////////////////////////////////////
+
+    // Calculate the needed buffer size (in characters) to convert the |str|
+    // parameter either to or from UTF8
+    // |len| - size of the input. -1 means it is 0-terminated
+    // Return value is either the size of the buffer needed to convert the whole
+    // input of size |len|, or, if |len| is -1, the size needed to convert a
+    // zero-terminated string, including the terminator character, or negative -
+    // if the size can't be calculated
+    static int calcUtf8BufferLength(const wchar_t* str, int len = -1);
+    static int calcUtf16BufferLength(const char* str, int len = -1);
+
+    // The following two functions convert |str| into the output buffer, instead
+    // of dynamically allocated class object.
+    // |str| - source string to convert, must be not null
+    // |len| - length of the source string, in chars; must be positive or -1.
+    //  -1 means 'the input is zero-terminated'. In that case output has to
+    //  be large enough to hold a zero character as well.
+    // |outStr| - the output buffer, must be not null
+    // |outLen| - the output buffer length, in chars; must be large enough to
+    //  hold the converted string. One can calculate the required length using
+    //  one of the getUtf<*>BufferLength() functions
+    //
+    // Returns a number of bytes written into the |outBuf|, or -1 on failure
+    //
+    // Note: you can't get the reason of the failure from this function call:
+    //  it could be bad input parameter (e.g. null buffer), too short output,
+    //  bad characters in the input string, even OS failure. So make sure
+    //  you do the call to getUtf<*>BufferLength() and all parameters are
+    //  correct - if you need to know the exact reason and not just "can't" one.
+    static int convertToUtf8(char* outStr, int outLen,
+                              const wchar_t* str, int len = -1);
+    static int convertFromUtf8(wchar_t* outStr, int outLen,
+                                const char* str, int len = -1);
+
+private:
+    wchar_t* mStr;
+    size_t mSize;
+};
+
+}  // namespace base
+}  // namespace android
+
+#endif  // _WIN32
diff --git a/base/Win32UnicodeString_unittest.cpp b/base/Win32UnicodeString_unittest.cpp
new file mode 100644
index 0000000..32e8e9e
--- /dev/null
+++ b/base/Win32UnicodeString_unittest.cpp
@@ -0,0 +1,228 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "android/base/system/Win32UnicodeString.h"
+
+#include <gtest/gtest.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+
+namespace android {
+namespace base {
+
+TEST(Win32UnicodeString, DefaultConstructor) {
+    Win32UnicodeString str;
+    EXPECT_EQ(0u, str.size());
+    EXPECT_STREQ(L"", str.c_str());
+    EXPECT_TRUE(str.data());
+}
+
+TEST(Win32UnicodeString, Constructors) {
+    static const struct {
+        const char* utf8;
+        const wchar_t* utf16;
+    } kData[] = {
+            {"", L""},
+            {"Hello World!", L"Hello World!"},
+            {"T\xC3\xA9l\xC3\xA9vision", L"T\xE9l\xE9vision"},
+            {"foo\xE1\x80\x80 bar", L"foo\x1000 bar"},
+    };
+    const size_t kDataSize = ARRAY_SIZE(kData);
+
+    for (size_t n = 0; n < kDataSize; ++n) {
+        Win32UnicodeString str1(kData[n].utf8);
+        EXPECT_EQ(wcslen(kData[n].utf16), str1.size());
+        EXPECT_STREQ(kData[n].utf16, str1.c_str());
+
+        Win32UnicodeString str2(kData[n].utf8, strlen(kData[n].utf8));
+        EXPECT_EQ(wcslen(kData[n].utf16), str2.size());
+        EXPECT_STREQ(kData[n].utf16, str2.c_str());
+
+        std::string baseStr(kData[n].utf8);
+        Win32UnicodeString str3(baseStr);
+        EXPECT_EQ(wcslen(kData[n].utf16), str3.size());
+        EXPECT_STREQ(kData[n].utf16, str3.c_str());
+
+        size_t utf16Len = wcslen(kData[n].utf16);
+        Win32UnicodeString str4(kData[n].utf16);
+        EXPECT_EQ(utf16Len, str4.size());
+        EXPECT_STREQ(kData[n].utf16, str4.c_str());
+
+        Win32UnicodeString str5 = str4;
+        EXPECT_EQ(utf16Len, str5.size());
+        EXPECT_STREQ(kData[n].utf16, str5.c_str());
+
+        Win32UnicodeString str6("foo");
+        str6 = str5;
+        EXPECT_EQ(utf16Len, str6.size());
+        EXPECT_STREQ(kData[n].utf16, str6.c_str());
+    }
+}
+
+TEST(Win32UnicodeString, convertToUtf8) {
+    static const struct {
+        const char* utf8;
+        const wchar_t* utf16;
+    } kData[] = {
+            {"", L""},
+            {"Hello World!", L"Hello World!"},
+            {"T\xC3\xA9l\xC3\xA9vision", L"T\xE9l\xE9vision"},
+            {"foo\xE1\x80\x80 bar", L"foo\x1000 bar"},
+    };
+    const size_t kDataSize = ARRAY_SIZE(kData);
+
+    for (size_t n = 0; n < kDataSize; ++n) {
+        std::string str1 = Win32UnicodeString::convertToUtf8(kData[n].utf16);
+        EXPECT_EQ(strlen(kData[n].utf8), str1.size());
+        EXPECT_STREQ(kData[n].utf8, str1.c_str());
+
+        std::string str2 = Win32UnicodeString::convertToUtf8(
+                kData[n].utf16, wcslen(kData[n].utf16));
+        EXPECT_EQ(strlen(kData[n].utf8), str2.size());
+        EXPECT_STREQ(kData[n].utf8, str2.c_str());
+
+        char out[256];
+        int len = Win32UnicodeString::convertToUtf8(out, sizeof(out),
+                                                    kData[n].utf16);
+        EXPECT_EQ(strlen(kData[n].utf8) + 1U, (size_t)len);
+        EXPECT_STREQ(kData[n].utf8, out);
+
+        len = Win32UnicodeString::convertToUtf8(out, sizeof(out),
+                                                kData[n].utf16,
+                                                wcslen(kData[n].utf16));
+        EXPECT_EQ((int)strlen(kData[n].utf8), len);
+        out[len] = 0;
+        EXPECT_STREQ(kData[n].utf8, out);
+
+        if (kData[n].utf8[0] != 0) {
+            len = Win32UnicodeString::convertToUtf8(out, 1,
+                                                    kData[n].utf16);
+            EXPECT_EQ(-1, len);
+        }
+
+        len = Win32UnicodeString::convertToUtf8(nullptr, 0,
+                                                kData[n].utf16);
+        EXPECT_EQ(-1, len);
+
+        len = Win32UnicodeString::convertToUtf8(nullptr, 0,
+                                                kData[n].utf16,
+                                                wcslen(kData[n].utf16));
+        EXPECT_EQ(-1, len);
+
+        len = Win32UnicodeString::calcUtf8BufferLength(kData[n].utf16);
+        EXPECT_EQ((int)strlen(kData[n].utf8) + 1, len);
+
+        len = Win32UnicodeString::calcUtf8BufferLength(kData[n].utf16,
+                                                      wcslen(kData[n].utf16));
+        EXPECT_EQ((int)strlen(kData[n].utf8), len);
+    }
+}
+
+TEST(Win32UnicodeString, convertFromUtf8) {
+    static const struct {
+        const char* utf8;
+        const wchar_t* utf16;
+    } kData[] = {
+            {"", L""},
+            {"Hello World!", L"Hello World!"},
+            {"T\xC3\xA9l\xC3\xA9vision", L"T\xE9l\xE9vision"},
+            {"foo\xE1\x80\x80 bar", L"foo\x1000 bar"},
+    };
+    const size_t kDataSize = ARRAY_SIZE(kData);
+
+    for (size_t n = 0; n < kDataSize; ++n) {
+        wchar_t out[256];
+        int len = Win32UnicodeString::convertFromUtf8(out, ARRAY_SIZE(out),
+                                                      kData[n].utf8);
+        EXPECT_EQ((int)wcslen(kData[n].utf16) + 1, len);
+        EXPECT_STREQ(kData[n].utf16, out);
+
+        len = Win32UnicodeString::convertFromUtf8(out, ARRAY_SIZE(out),
+                                                  kData[n].utf8,
+                                                  strlen(kData[n].utf8));
+        EXPECT_EQ((int)wcslen(kData[n].utf16), len);
+        out[len] = 0;
+        EXPECT_STREQ(kData[n].utf16, out);
+
+        if (kData[n].utf16[0] != 0) {
+            len = Win32UnicodeString::convertFromUtf8(out, 1, kData[n].utf8);
+            EXPECT_EQ(-1, len);
+        }
+
+        len = Win32UnicodeString::convertFromUtf8(nullptr, 0, kData[n].utf8);
+        EXPECT_EQ(-1, len);
+
+        len = Win32UnicodeString::convertFromUtf8(nullptr, 0,
+                                                  kData[n].utf8,
+                                                  strlen(kData[n].utf8));
+        EXPECT_EQ(-1, len);
+
+        len = Win32UnicodeString::calcUtf16BufferLength(kData[n].utf8);
+        EXPECT_EQ((int)wcslen(kData[n].utf16) + 1, len);
+
+        len = Win32UnicodeString::calcUtf16BufferLength(kData[n].utf8,
+                                                       strlen(kData[n].utf8));
+        EXPECT_EQ((int)wcslen(kData[n].utf16), len);
+    }
+}
+
+TEST(Win32UnicodeString, appending) {
+    static const struct {
+        const wchar_t* first;
+        const wchar_t* second;
+        const wchar_t* result;
+    } kData[] = {
+        {L"foo", L"bar", L"foobar"},
+        {L"", L"bar", L"bar"},
+        {L"foo", L"", L"foo"},
+        {L"foobar", L" with ice cream", L"foobar with ice cream"},
+    };
+
+    for (const auto& data : kData) {
+        {
+            // Test appending Win32UnicodeString
+            Win32UnicodeString first(data.first);
+            Win32UnicodeString second(data.second);
+
+            first.append(second);
+            EXPECT_EQ(wcslen(data.result), first.size());
+            EXPECT_STREQ(data.result, first.c_str());
+        }
+        {
+            // Test appending wchar_t*
+            Win32UnicodeString str(data.first);
+            str.append(data.second);
+            EXPECT_EQ(wcslen(data.result), str.size());
+            EXPECT_STREQ(data.result, str.c_str());
+        }
+        {
+            // Test appending wchar_t* with length
+            Win32UnicodeString str(data.first);
+            str.append(data.second, wcslen(data.second));
+            EXPECT_EQ(wcslen(data.result), str.size());
+            EXPECT_STREQ(data.result, str.c_str());
+        }
+        if (wcslen(data.second) > 0) {
+            // Test appending with fewer characters
+            Win32UnicodeString str(data.first);
+            str.append(data.second, wcslen(data.second) - 1);
+            EXPECT_EQ(wcslen(data.result) - 1, str.size());
+            std::wstring choppedResult(data.result, wcslen(data.result) - 1);
+            EXPECT_STREQ(choppedResult.c_str(), str.c_str());
+        }
+    }
+}
+
+}  // namespace base
+}  // namespace android