Move secondary dex files processing in the app process

Run the validation and processing of secondary dex files with the app
process capabilities. This drops the need to validate/use real paths since
all file tests and accesses is done now with lower privileges.

The oat files and profiles are now created relative to the given path
instead of using realpath. This allows us to always know where the
compiler artifacts are even if the original dex file was deleted. It
enables a straightforward clean up during reconciliation.

The validation will accept /data/user/0 as a valid secondary dex path
since for user 0 this is the location that will be used most of the times.

This CL also adds a test framework for dexopt related functionality.
The current tests only cover the secondary dex files with more to come.

Bug: 64460009
Test: adb shell cmd package reconcile-secondary-dex-files
com.google.android.googlequicksearchbox (after removing some files)
      adb shell cmd package compile -m speed --secondary-dex
com.google.android.googlequicksearchbox
      adb shell /data/nativetest64/installd_utils_test/installd_utils_test

Change-Id: I0d49cd7f3c089bc5156178680bb29b75ab82092c
diff --git a/cmds/installd/tests/test_utils.h b/cmds/installd/tests/test_utils.h
new file mode 100644
index 0000000..7d1162e
--- /dev/null
+++ b/cmds/installd/tests/test_utils.h
@@ -0,0 +1,107 @@
+#include <android-base/logging.h>
+#include <stdlib.h>
+#include <string.h>
+
+uint8_t kBase64Map[256] = {
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
+     52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
+    255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
+      7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
+     19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
+    255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
+     37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
+     49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255
+};
+
+uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
+    CHECK(dst_size != nullptr);
+    std::vector<uint8_t> tmp;
+    uint32_t t = 0, y = 0;
+    int g = 3;
+    for (size_t i = 0; src[i] != '\0'; ++i) {
+        uint8_t c = kBase64Map[src[i] & 0xFF];
+        if (c == 255) continue;
+        // the final = symbols are read and used to trim the remaining bytes
+        if (c == 254) {
+            c = 0;
+            // prevent g < 0 which would potentially allow an overflow later
+            if (--g < 0) {
+                *dst_size = 0;
+                return nullptr;
+            }
+        } else if (g != 3) {
+            // we only allow = to be at the end
+            *dst_size = 0;
+            return nullptr;
+        }
+        t = (t << 6) | c;
+        if (++y == 4) {
+            tmp.push_back((t >> 16) & 255);
+            if (g > 1) {
+                tmp.push_back((t >> 8) & 255);
+            }
+            if (g > 2) {
+                tmp.push_back(t & 255);
+            }
+            y = t = 0;
+        }
+    }
+    if (y != 0) {
+        *dst_size = 0;
+        return nullptr;
+    }
+    std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
+    *dst_size = tmp.size();
+    std::copy(tmp.begin(), tmp.end(), dst.get());
+    return dst.release();
+}
+
+bool WriteBase64ToFile(const char* base64, const std::string& file,
+        uid_t uid, gid_t gid, int mode) {
+    CHECK(base64 != nullptr);
+    size_t length;
+    std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length));
+    CHECK(bytes != nullptr);
+
+
+    int fd = open(file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+
+    if (fd < 0) {
+        PLOG(ERROR) << "Could not open file " << file;
+        return false;
+    }
+
+    size_t wrote = 0;
+    while (wrote < length) {
+        ssize_t cur = write(fd, bytes.get() + wrote, length - wrote);
+        if (cur == -1) {
+            PLOG(ERROR) << "Could not write file " << file;
+            return false;
+        }
+        wrote += cur;
+    }
+
+    if (::chown(file.c_str(), uid, gid) != 0) {
+        PLOG(ERROR) << "Could not chown file " << file;
+        return false;
+    }
+    if (::chmod(file.c_str(), mode) != 0) {
+        PLOG(ERROR) << "Could not chmod file " << file;
+        return false;
+    }
+    return true;
+}