Merge "Expose display manager client event fd"
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
index d1bdded..6caf149 100644
--- a/cmds/installd/CacheItem.cpp
+++ b/cmds/installd/CacheItem.cpp
@@ -16,8 +16,9 @@
 
 #include "CacheItem.h"
 
-#include <stdint.h>
 #include <inttypes.h>
+#include <stdint.h>
+#include <sys/xattr.h>
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
@@ -29,12 +30,23 @@
 namespace android {
 namespace installd {
 
-CacheItem::CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p) : mParent(parent) {
+CacheItem::CacheItem(FTSENT* p) {
     level = p->fts_level;
     directory = S_ISDIR(p->fts_statp->st_mode);
     size = p->fts_statp->st_blocks * 512;
     modified = p->fts_statp->st_mtime;
-    mName = p->fts_path;
+
+    mParent = static_cast<CacheItem*>(p->fts_parent->fts_pointer);
+    if (mParent) {
+        atomic = mParent->atomic;
+        tombstone = mParent->tombstone;
+        mName = p->fts_name;
+        mName.insert(0, "/");
+    } else {
+        atomic = false;
+        tombstone = false;
+        mName = p->fts_path;
+    }
 }
 
 CacheItem::~CacheItem() {
@@ -46,7 +58,7 @@
 
 std::string CacheItem::buildPath() {
     std::string res = mName;
-    std::shared_ptr<CacheItem> parent = mParent;
+    CacheItem* parent = mParent;
     while (parent) {
         res.insert(0, parent->mName);
         parent = parent->mParent;
@@ -57,13 +69,47 @@
 int CacheItem::purge() {
     auto path = buildPath();
     if (directory) {
-        return delete_dir_contents_and_dir(path, true);
-    } else {
-        int res = unlink(path.c_str());
-        if (res != 0) {
-            PLOG(WARNING) << "Failed to unlink " << path;
+        FTS *fts;
+        FTSENT *p;
+        char *argv[] = { (char*) path.c_str(), nullptr };
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+            PLOG(WARNING) << "Failed to fts_open " << path;
+            return -1;
         }
-        return res;
+        while ((p = fts_read(fts)) != nullptr) {
+            switch (p->fts_info) {
+            case FTS_D:
+                if (p->fts_level == 0) {
+                    p->fts_number = tombstone;
+                } else {
+                    p->fts_number = p->fts_parent->fts_number
+                            | (getxattr(p->fts_path, kXattrCacheTombstone, nullptr, 0) >= 0);
+                }
+                break;
+            case FTS_F:
+                if (p->fts_parent->fts_number) {
+                    truncate(p->fts_path, 0);
+                } else {
+                    unlink(p->fts_path);
+                }
+                break;
+            case FTS_DEFAULT:
+            case FTS_SL:
+            case FTS_SLNONE:
+                unlink(p->fts_path);
+                break;
+            case FTS_DP:
+                rmdir(p->fts_path);
+                break;
+            }
+        }
+        return 0;
+    } else {
+        if (tombstone) {
+            return truncate(path.c_str(), 0);
+        } else {
+            return unlink(path.c_str());
+        }
     }
 }
 
diff --git a/cmds/installd/CacheItem.h b/cmds/installd/CacheItem.h
index bec8bc8..afbb15d 100644
--- a/cmds/installd/CacheItem.h
+++ b/cmds/installd/CacheItem.h
@@ -36,7 +36,7 @@
  */
 class CacheItem {
 public:
-    CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p);
+    CacheItem(FTSENT* p);
     ~CacheItem();
 
     std::string toString();
@@ -46,11 +46,13 @@
 
     short level;
     bool directory;
+    bool atomic;
+    bool tombstone;
     int64_t size;
     time_t modified;
 
 private:
-    std::shared_ptr<CacheItem> mParent;
+    CacheItem* mParent;
     std::string mName;
 
     DISALLOW_COPY_AND_ASSIGN(CacheItem);
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index 23c4330..9377836 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -20,6 +20,7 @@
 
 #include <fts.h>
 #include <sys/quota.h>
+#include <sys/xattr.h>
 #include <utils/Trace.h>
 
 #include <android-base/logging.h>
@@ -86,30 +87,59 @@
         PLOG(WARNING) << "Failed to fts_open " << path;
         return;
     }
-    // TODO: add support for "user.atomic" and "user.tombstone" xattrs
-    while ((p = fts_read(fts)) != NULL) {
+    while ((p = fts_read(fts)) != nullptr) {
+        if (p->fts_level == 0) continue;
+
+        // Create tracking nodes for everything we encounter
         switch (p->fts_info) {
         case FTS_D:
-            // Track the newest mtime of anything inside so we consider
-            // deleting the directory last
-            p->fts_number = p->fts_statp->st_mtime;
-            break;
-        case FTS_DP:
-            p->fts_statp->st_mtime = p->fts_number;
-
-            // Ignore the actual top-level cache directories
-            if (p->fts_level == 0) break;
         case FTS_DEFAULT:
         case FTS_F:
         case FTS_SL:
-        case FTS_SLNONE:
-            // TODO: optimize path memory footprint
-            items.push_back(std::shared_ptr<CacheItem>(new CacheItem(nullptr, p)));
+        case FTS_SLNONE: {
+            auto item = std::shared_ptr<CacheItem>(new CacheItem(p));
+            p->fts_pointer = static_cast<void*>(item.get());
+            items.push_back(item);
+        }
+        }
 
-            // Track the newest modified item under this tree
-            p->fts_parent->fts_number =
-                    std::max(p->fts_parent->fts_number, p->fts_statp->st_mtime);
-            break;
+        switch (p->fts_info) {
+        case FTS_D: {
+            auto item = static_cast<CacheItem*>(p->fts_pointer);
+            item->atomic |= (getxattr(p->fts_path, kXattrCacheAtomic, nullptr, 0) >= 0);
+            item->tombstone |= (getxattr(p->fts_path, kXattrCacheTombstone, nullptr, 0) >= 0);
+
+            // When atomic, immediately collect all files under tree
+            if (item->atomic) {
+                while ((p = fts_read(fts)) != nullptr) {
+                    if (p->fts_info == FTS_DP && p->fts_level == item->level) break;
+                    switch (p->fts_info) {
+                    case FTS_D:
+                    case FTS_DEFAULT:
+                    case FTS_F:
+                    case FTS_SL:
+                    case FTS_SLNONE:
+                        item->size += p->fts_statp->st_blocks * 512;
+                        item->modified = std::max(item->modified, p->fts_statp->st_mtime);
+                    }
+                }
+            }
+        }
+        }
+
+        // Bubble up modified time to parent
+        switch (p->fts_info) {
+        case FTS_DP:
+        case FTS_DEFAULT:
+        case FTS_F:
+        case FTS_SL:
+        case FTS_SLNONE: {
+            auto item = static_cast<CacheItem*>(p->fts_pointer);
+            auto parent = static_cast<CacheItem*>(p->fts_parent->fts_pointer);
+            if (parent) {
+                parent->modified = std::max(parent->modified, item->modified);
+            }
+        }
         }
     }
     fts_close(fts);
@@ -137,7 +167,7 @@
         }
         return left->directory;
     };
-    std::sort(items.begin(), items.end(), cmp);
+    std::stable_sort(items.begin(), items.end(), cmp);
     ATRACE_END();
 }
 
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index aa10666..a84b051 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -86,7 +86,8 @@
 static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
 static constexpr int FLAG_USE_QUOTA = 1 << 12;
 static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
-static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 14;
+static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
+static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 15;
 
 namespace {
 
@@ -833,6 +834,14 @@
         ATRACE_BEGIN("bounce");
         std::shared_ptr<CacheTracker> active;
         while (active || !queue.empty()) {
+            // Only look at apps under quota when explicitly requested
+            if (active && (active->getCacheRatio() < 10000)
+                    && !(flags & FLAG_FREE_CACHE_V2_DEFY_QUOTA)) {
+                LOG(DEBUG) << "Active ratio " << active->getCacheRatio()
+                        << " isn't over quota, and defy not requested";
+                break;
+            }
+
             // Find the best tracker to work with; this might involve swapping
             // if the active tracker is no longer the most over quota
             bool nextBetter = active && !queue.empty()
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index a32df22..b5b080d 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -14,3 +14,22 @@
         "libdiskusage",
     ],
 }
+
+cc_test {
+    name: "installd_cache_test",
+    clang: true,
+    srcs: ["installd_cache_test.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "liblog",
+        "liblogwrap",
+        "libselinux",
+        "libutils",
+    ],
+    static_libs: [
+        "libinstalld",
+        "libdiskusage",
+    ],
+}
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
new file mode 100644
index 0000000..50a47d2
--- /dev/null
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/statvfs.h>
+#include <sys/xattr.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+
+#include "InstalldNativeService.h"
+#include "globals.h"
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+constexpr const char* kTestUuid = "TEST";
+
+constexpr int64_t kKbInBytes = 1024;
+constexpr int64_t kMbInBytes = 1024 * kKbInBytes;
+constexpr int64_t kGbInBytes = 1024 * kMbInBytes;
+constexpr int64_t kTbInBytes = 1024 * kGbInBytes;
+
+static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
+static constexpr int FLAG_FREE_CACHE_V2_DEFY_QUOTA = 1 << 14;
+
+int get_property(const char *key, char *value, const char *default_value) {
+    return property_get(key, value, default_value);
+}
+
+bool calculate_oat_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+        const char *oat_dir ATTRIBUTE_UNUSED,
+        const char *apk_path ATTRIBUTE_UNUSED,
+        const char *instruction_set ATTRIBUTE_UNUSED) {
+    return false;
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+        const char *apk_path ATTRIBUTE_UNUSED,
+        const char *instruction_set ATTRIBUTE_UNUSED) {
+    return false;
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX] ATTRIBUTE_UNUSED,
+        const char *src ATTRIBUTE_UNUSED,
+        const char *instruction_set ATTRIBUTE_UNUSED) {
+    return false;
+}
+
+static void mkdir(const char* path) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    ::mkdir(fullPath, 0755);
+}
+
+static void touch(const char* path, int len, int time) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    int fd = ::open(fullPath, O_RDWR | O_CREAT, 0644);
+    ::fallocate(fd, 0, 0, len);
+    ::close(fd);
+    struct utimbuf times;
+    times.actime = times.modtime = std::time(0) + time;
+    ::utime(fullPath, &times);
+}
+
+static int exists(const char* path) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    return ::access(fullPath, F_OK);
+}
+
+static int64_t size(const char* path) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    struct stat buf;
+    if (!stat(fullPath, &buf)) {
+        return buf.st_size;
+    } else {
+        return -1;
+    }
+}
+
+static int64_t free() {
+    struct statvfs buf;
+    if (!statvfs("/data/local/tmp", &buf)) {
+        return buf.f_bavail * buf.f_bsize;
+    } else {
+        return -1;
+    }
+}
+
+static void setxattr(const char* path, const char* key) {
+    const char* fullPath = StringPrintf("/data/local/tmp/user/0/%s", path).c_str();
+    ::setxattr(fullPath, key, "", 0, 0);
+}
+
+class CacheTest : public testing::Test {
+protected:
+    InstalldNativeService* service;
+    std::unique_ptr<std::string> testUuid;
+
+    virtual void SetUp() {
+        setenv("ANDROID_LOG_TAGS", "*:v", 1);
+        android::base::InitLogging(nullptr);
+
+        service = new InstalldNativeService();
+        testUuid = std::make_unique<std::string>();
+        *testUuid = std::string(kTestUuid);
+        system("mkdir -p /data/local/tmp/user/0");
+    }
+
+    virtual void TearDown() {
+        delete service;
+        system("rm -rf /data/local/tmp/user");
+    }
+};
+
+TEST_F(CacheTest, FreeCache_All) {
+    mkdir("com.example");
+    touch("com.example/normal", 1 * kMbInBytes, 60);
+    mkdir("com.example/cache");
+    mkdir("com.example/cache/foo");
+    touch("com.example/cache/foo/one", 1 * kMbInBytes, 60);
+    touch("com.example/cache/foo/two", 2 * kMbInBytes, 120);
+
+    EXPECT_EQ(0, exists("com.example/normal"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/one"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+
+    service->freeCache(testUuid, kTbInBytes,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(0, exists("com.example/normal"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
+}
+
+TEST_F(CacheTest, FreeCache_Age) {
+    mkdir("com.example");
+    mkdir("com.example/cache");
+    mkdir("com.example/cache/foo");
+    touch("com.example/cache/foo/one", kMbInBytes, 60);
+    touch("com.example/cache/foo/two", kMbInBytes, 120);
+
+    service->freeCache(testUuid, free() + kKbInBytes,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/two"));
+
+    service->freeCache(testUuid, free() + kKbInBytes,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, exists("com.example/cache/foo/one"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/two"));
+}
+
+TEST_F(CacheTest, FreeCache_Tombstone) {
+    mkdir("com.example");
+    mkdir("com.example/cache");
+    mkdir("com.example/cache/foo");
+    touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
+    touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 60);
+    mkdir("com.example/cache/bar");
+    touch("com.example/cache/bar/bar1", 2 * kMbInBytes, 120);
+    touch("com.example/cache/bar/bar2", 2 * kMbInBytes, 120);
+
+    setxattr("com.example/cache/bar", "user.cache_tombstone");
+
+    EXPECT_EQ(0, exists("com.example/cache/foo/foo1"));
+    EXPECT_EQ(0, exists("com.example/cache/foo/foo2"));
+    EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
+    EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
+    EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar1"));
+    EXPECT_EQ(2 * kMbInBytes, size("com.example/cache/bar/bar2"));
+
+    service->freeCache(testUuid, kTbInBytes,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
+    EXPECT_EQ(0, exists("com.example/cache/bar/bar1"));
+    EXPECT_EQ(0, exists("com.example/cache/bar/bar2"));
+    EXPECT_EQ(0, size("com.example/cache/bar/bar1"));
+    EXPECT_EQ(0, size("com.example/cache/bar/bar2"));
+}
+
+TEST_F(CacheTest, FreeCache_Atomic) {
+    mkdir("com.example");
+    mkdir("com.example/cache");
+    mkdir("com.example/cache/foo");
+    touch("com.example/cache/foo/foo1", 1 * kMbInBytes, 60);
+    touch("com.example/cache/foo/foo2", 1 * kMbInBytes, 120);
+
+    setxattr("com.example/cache/foo", "user.cache_atomic");
+
+    service->freeCache(testUuid, free() + kKbInBytes,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, exists("com.example/cache/foo/foo1"));
+    EXPECT_EQ(-1, exists("com.example/cache/foo/foo2"));
+}
+
+TEST_F(CacheTest, FreeCache_AtomicTombstone) {
+    LOG(INFO) << "FreeCache_AtomicTombstone";
+
+    mkdir("com.example");
+    mkdir("com.example/cache");
+
+    // this dir must look really old for some reason?
+    mkdir("com.example/cache/atomic");
+    touch("com.example/cache/atomic/file1", kMbInBytes, 120);
+    touch("com.example/cache/atomic/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/atomic/dir");
+    touch("com.example/cache/atomic/dir/file1", kMbInBytes, 120);
+    touch("com.example/cache/atomic/dir/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/atomic/tomb");
+    touch("com.example/cache/atomic/tomb/file1", kMbInBytes, 120);
+    touch("com.example/cache/atomic/tomb/file2", kMbInBytes, 120);
+    mkdir("com.example/cache/atomic/tomb/dir");
+    touch("com.example/cache/atomic/tomb/dir/file1", kMbInBytes, 120);
+    touch("com.example/cache/atomic/tomb/dir/file2", kMbInBytes, 120);
+
+    mkdir("com.example/cache/tomb");
+    touch("com.example/cache/tomb/file1", kMbInBytes, 240);
+    touch("com.example/cache/tomb/file2", kMbInBytes, 240);
+    mkdir("com.example/cache/tomb/dir");
+    touch("com.example/cache/tomb/dir/file1", kMbInBytes, 240);
+    touch("com.example/cache/tomb/dir/file2", kMbInBytes, 240);
+    mkdir("com.example/cache/tomb/atomic");
+    touch("com.example/cache/tomb/atomic/file1", kMbInBytes, 60);
+    touch("com.example/cache/tomb/atomic/file2", kMbInBytes, 60);
+    mkdir("com.example/cache/tomb/atomic/dir");
+    touch("com.example/cache/tomb/atomic/dir/file1", kMbInBytes, 60);
+    touch("com.example/cache/tomb/atomic/dir/file2", kMbInBytes, 60);
+
+    setxattr("com.example/cache/atomic", "user.cache_atomic");
+    setxattr("com.example/cache/atomic/tomb", "user.cache_tombstone");
+    setxattr("com.example/cache/tomb", "user.cache_tombstone");
+    setxattr("com.example/cache/tomb/atomic", "user.cache_atomic");
+
+    service->freeCache(testUuid, free() + kKbInBytes,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/dir/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/atomic/tomb/dir/file2"));
+
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+
+    service->freeCache(testUuid, free() + kKbInBytes,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, size("com.example/cache/atomic/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/atomic/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file1"));
+    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file2"));
+    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file2"));
+
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/file2"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file1"));
+    EXPECT_EQ(kMbInBytes, size("com.example/cache/tomb/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+
+    service->freeCache(testUuid, kTbInBytes,
+            FLAG_FREE_CACHE_V2 | FLAG_FREE_CACHE_V2_DEFY_QUOTA);
+
+    EXPECT_EQ(-1, size("com.example/cache/atomic/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/atomic/file2"));
+    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file1"));
+    EXPECT_EQ(-1, size("com.example/cache/atomic/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file1"));
+    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/file2"));
+    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/atomic/tomb/dir/file2"));
+
+    EXPECT_EQ(0, size("com.example/cache/tomb/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/dir/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/file2"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file1"));
+    EXPECT_EQ(0, size("com.example/cache/tomb/atomic/dir/file2"));
+}
+
+}  // namespace installd
+}  // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 947cc0d..4b68574 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -29,6 +29,7 @@
 #define TEST_DATA_DIR "/data/"
 #define TEST_APP_DIR "/data/app/"
 #define TEST_APP_PRIVATE_DIR "/data/app-private/"
+#define TEST_APP_EPHEMERAL_DIR "/data/app-ephemeral/"
 #define TEST_ASEC_DIR "/mnt/asec/"
 #define TEST_EXPAND_DIR "/mnt/expand/"
 
@@ -57,6 +58,9 @@
         android_app_private_dir.path = (char*) TEST_APP_PRIVATE_DIR;
         android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR);
 
+        android_app_ephemeral_dir.path = (char*) TEST_APP_EPHEMERAL_DIR;
+        android_app_ephemeral_dir.len = strlen(TEST_APP_EPHEMERAL_DIR);
+
         android_data_dir.path = (char*) TEST_DATA_DIR;
         android_data_dir.len = strlen(TEST_DATA_DIR);
 
@@ -85,19 +89,19 @@
     // Bad prefixes directories
     const char *badprefix1 = "/etc/passwd";
     EXPECT_EQ(-1, validate_apk_path(badprefix1))
-            << badprefix1 << " should be allowed as a valid path";
+            << badprefix1 << " should not be allowed as a valid path";
 
     const char *badprefix2 = "../.." TEST_APP_DIR "../../../blah";
     EXPECT_EQ(-1, validate_apk_path(badprefix2))
-            << badprefix2 << " should be allowed as a valid path";
+            << badprefix2 << " should not be allowed as a valid path";
 
     const char *badprefix3 = "init.rc";
     EXPECT_EQ(-1, validate_apk_path(badprefix3))
-            << badprefix3 << " should be allowed as a valid path";
+            << badprefix3 << " should not be allowed as a valid path";
 
     const char *badprefix4 = "/init.rc";
     EXPECT_EQ(-1, validate_apk_path(badprefix4))
-            << badprefix4 << " should be allowed as a valid path";
+            << badprefix4 << " should not be allowed as a valid path";
 }
 
 TEST_F(UtilsTest, IsValidApkPath_Internal) {
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 37215ea..6d50f55 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -33,6 +33,7 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <cutils/fs.h>
+#include <cutils/properties.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
@@ -155,6 +156,9 @@
 std::string create_data_path(const char* volume_uuid) {
     if (volume_uuid == nullptr) {
         return "/data";
+    } else if (!strcmp(volume_uuid, "TEST")) {
+        CHECK(property_get_bool("ro.debuggable", false));
+        return "/data/local/tmp";
     } else {
         CHECK(is_valid_filename(volume_uuid));
         return StringPrintf("/mnt/expand/%s", volume_uuid);
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 5226d1c..aa83dc2 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -66,6 +66,8 @@
 
 constexpr const char* kXattrInodeCache = "user.inode_cache";
 constexpr const char* kXattrInodeCodeCache = "user.inode_code_cache";
+constexpr const char* kXattrCacheAtomic = "user.cache_atomic";
+constexpr const char* kXattrCacheTombstone = "user.cache_tombstone";
 
 int create_pkg_path(char path[PKG_PATH_MAX],
                     const char *pkgname,
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index ce058c8..6fd9b21 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -469,9 +469,17 @@
     return status;
 }
 
+void signalHandler(int sig) {
+    if (sig == SIGINT) {
+        int retVal;
+        pthread_exit(&retVal);
+    }
+}
+
 }  // namespace lshal
 }  // namespace android
 
 int main(int argc, char **argv) {
+    signal(SIGINT, ::android::lshal::signalHandler);
     return ::android::lshal::Lshal{}.main(argc, argv);
 }
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index 001c3d6..ca477bf 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -29,7 +29,8 @@
 
 class BackgroundTaskState {
 public:
-    BackgroundTaskState(){}
+    BackgroundTaskState(std::function<void(void)> &&func)
+            : mFunc(std::forward<decltype(func)>(func)) {}
     void notify() {
         std::unique_lock<std::mutex> lock(mMutex);
         mFinished = true;
@@ -42,22 +43,37 @@
         mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
         return mFinished;
     }
+    void operator()() {
+        mFunc();
+    }
 private:
     std::mutex mMutex;
     std::condition_variable mCondVar;
     bool mFinished = false;
+    std::function<void(void)> mFunc;
 };
 
+void *callAndNotify(void *data) {
+    BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
+    state();
+    state.notify();
+    return NULL;
+}
+
 template<class R, class P>
-bool timeout(std::chrono::duration<R, P> delay, const std::function<void(void)> &func) {
+bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) {
     auto now = std::chrono::system_clock::now();
-    BackgroundTaskState state{};
-    std::thread t([&state, &func] {
-        func();
-        state.notify();
-    });
-    t.detach();
+    BackgroundTaskState state{std::forward<decltype(func)>(func)};
+    pthread_t thread;
+    if (pthread_create(&thread, NULL, callAndNotify, &state)) {
+        std::cerr << "FATAL: could not create background thread." << std::endl;
+        return false;
+    }
     bool success = state.wait(now + delay);
+    if (!success) {
+        pthread_kill(thread, SIGINT);
+    }
+    pthread_join(thread, NULL);
     return success;
 }
 
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 5309acf..bb70c5c 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -25,7 +25,13 @@
 
 DisplayService::DisplayService(Hwc2::Composer* hidl)
     : BASE("DisplayService", Endpoint::Create(DisplayRPC::kClientPath)),
-      hardware_composer_(hidl) {}
+      hardware_composer_(hidl) {
+  hardware_composer_.Initialize();
+}
+
+bool DisplayService::IsInitialized() const {
+  return BASE::IsInitialized() && hardware_composer_.IsInitialized();
+}
 
 std::string DisplayService::DumpState(size_t max_length) {
   std::vector<char> buffer(max_length);
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 5de4f1d..b207e4d 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -23,6 +23,7 @@
 // DisplayService implements the displayd display service over ServiceFS.
 class DisplayService : public pdx::ServiceBase<DisplayService> {
  public:
+  bool IsInitialized() const override;
   std::string DumpState(size_t max_length) override;
 
   void OnChannelClose(pdx::Message& message,
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index e6ed665..f801d9b 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -100,7 +100,8 @@
 }
 
 HardwareComposer::HardwareComposer(Hwc2::Composer* hwc2_hidl)
-    : hwc2_hidl_(hwc2_hidl),
+    : initialized_(false),
+      hwc2_hidl_(hwc2_hidl),
       display_transform_(HWC_TRANSFORM_NONE),
       display_surfaces_updated_(false),
       hardware_layers_need_update_(false),
@@ -126,6 +127,51 @@
   Suspend();
 }
 
+bool HardwareComposer::Initialize() {
+  if (initialized_) {
+    ALOGE("HardwareComposer::Initialize: already initialized.");
+    return false;
+  }
+
+  int32_t ret = HWC2_ERROR_NONE;
+
+  Hwc2::Config config;
+  ret = (int32_t)hwc2_hidl_->getActiveConfig(HWC_DISPLAY_PRIMARY, &config);
+
+  if (ret != HWC2_ERROR_NONE) {
+    ALOGE("HardwareComposer: Failed to get current display config : %d",
+          config);
+    return false;
+  }
+
+  ret =
+      GetDisplayMetrics(HWC_DISPLAY_PRIMARY, config, &native_display_metrics_);
+
+  if (ret != HWC2_ERROR_NONE) {
+    ALOGE(
+        "HardwareComposer: Failed to get display attributes for current "
+        "configuration : %d",
+        ret);
+    return false;
+  }
+
+  ALOGI(
+      "HardwareComposer: primary display attributes: width=%d height=%d "
+      "vsync_period_ns=%d DPI=%dx%d",
+      native_display_metrics_.width, native_display_metrics_.height,
+      native_display_metrics_.vsync_period_ns, native_display_metrics_.dpi.x,
+      native_display_metrics_.dpi.y);
+
+  // Set the display metrics but never use rotation to avoid the long latency of
+  // rotation processing in hwc.
+  display_transform_ = HWC_TRANSFORM_NONE;
+  display_metrics_ = native_display_metrics_;
+
+  initialized_ = true;
+
+  return initialized_;
+}
+
 bool HardwareComposer::Resume() {
   std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
   if (post_thread_state_ == PostThreadState::kRunning) {
@@ -136,62 +182,6 @@
 
   int32_t ret = HWC2_ERROR_NONE;
 
-  static const uint32_t attributes[] = {
-      HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_VSYNC_PERIOD,
-      HWC_DISPLAY_DPI_X, HWC_DISPLAY_DPI_Y,  HWC_DISPLAY_NO_ATTRIBUTE,
-  };
-
-  std::vector<Hwc2::Config> configs;
-  ret = (int32_t)hwc2_hidl_->getDisplayConfigs(HWC_DISPLAY_PRIMARY, &configs);
-
-  if (ret != HWC2_ERROR_NONE) {
-    ALOGE("HardwareComposer: Failed to get display configs");
-    return false;
-  }
-
-  uint32_t num_configs = configs.size();
-
-  for (size_t i = 0; i < num_configs; i++) {
-    ALOGI("HardwareComposer: cfg[%zd/%zd] = 0x%08x", i, num_configs,
-          configs[i]);
-
-    ret = GetDisplayMetrics(HWC_DISPLAY_PRIMARY, configs[i],
-                            &native_display_metrics_);
-
-    if (ret != HWC2_ERROR_NONE) {
-      ALOGE("HardwareComposer: Failed to get display attributes %d", ret);
-      continue;
-    } else {
-      ret =
-          (int32_t)hwc2_hidl_->setActiveConfig(HWC_DISPLAY_PRIMARY, configs[i]);
-
-      if (ret != HWC2_ERROR_NONE) {
-        ALOGE("HardwareComposer: Failed to set display configuration; ret=%d",
-              ret);
-        continue;
-      }
-
-      break;
-    }
-  }
-
-  if (ret != HWC2_ERROR_NONE) {
-    ALOGE("HardwareComposer: Could not set a valid display configuration.");
-    return false;
-  }
-
-  // Set the display metrics but never use rotation to avoid the long latency of
-  // rotation processing in hwc.
-  display_transform_ = HWC_TRANSFORM_NONE;
-  display_metrics_ = native_display_metrics_;
-
-  ALOGI(
-      "HardwareComposer: primary display attributes: width=%d height=%d "
-      "vsync_period_ns=%d DPI=%dx%d",
-      native_display_metrics_.width, native_display_metrics_.height,
-      native_display_metrics_.vsync_period_ns, native_display_metrics_.dpi.x,
-      native_display_metrics_.dpi.y);
-
   // Always turn off vsync when we start.
   EnableVsync(false);
 
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index b6aa807..e2a8b90 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -189,6 +189,10 @@
   HardwareComposer(Hwc2::Composer* hidl);
   ~HardwareComposer();
 
+  bool Initialize();
+
+  bool IsInitialized() const { return initialized_; }
+
   bool Suspend();
   bool Resume();
 
@@ -303,6 +307,8 @@
 
   void HandlePendingScreenshots();
 
+  bool initialized_;
+
   // Hardware composer HAL device.
   std::unique_ptr<Hwc2::Composer> hwc2_hidl_;
   sp<ComposerCallback> callbacks_;
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index 18ec5e3..7062c57 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -246,6 +246,19 @@
  */
 static int getNeededCount(GLint pname) {
     int needed = 1;
+#ifdef GL_ES_VERSION_3_0
+    // GLES 3.x pnames
+    switch (pname) {
+        case GL_MAX_VIEWPORT_DIMS:
+            needed = 2;
+            break;
+
+        case GL_PROGRAM_BINARY_FORMATS:
+            glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &needed);
+            break;
+    }
+#endif
+
 #ifdef GL_ES_VERSION_2_0
     // GLES 2.x pnames
     switch (pname) {
diff --git a/services/vr/vr_window_manager/composer/1.0/Android.bp b/services/vr/vr_window_manager/composer/1.0/Android.bp
index 5e791a7..58f83f8 100644
--- a/services/vr/vr_window_manager/composer/1.0/Android.bp
+++ b/services/vr/vr_window_manager/composer/1.0/Android.bp
@@ -6,13 +6,9 @@
     cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hidl:system/libhidl/transport -randroid.hardware:hardware/interfaces/ -randroid.dvr:frameworks/native/services/vr/vr_window_manager android.dvr.composer@1.0",
     srcs: [
         "IVrComposerClient.hal",
-        "IVrComposerView.hal",
-        "IVrComposerCallback.hal",
     ],
     out: [
         "android/dvr/composer/1.0/VrComposerClientAll.cpp",
-        "android/dvr/composer/1.0/VrComposerViewAll.cpp",
-        "android/dvr/composer/1.0/VrComposerCallbackAll.cpp",
     ],
 }
 
@@ -22,8 +18,6 @@
     cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hidl:system/libhidl/transport -randroid.hardware:hardware/interfaces/ -randroid.dvr:frameworks/native/services/vr/vr_window_manager android.dvr.composer@1.0",
     srcs: [
         "IVrComposerClient.hal",
-        "IVrComposerView.hal",
-        "IVrComposerCallback.hal",
     ],
     out: [
         "android/dvr/composer/1.0/IVrComposerClient.h",
@@ -31,18 +25,6 @@
         "android/dvr/composer/1.0/BnHwVrComposerClient.h",
         "android/dvr/composer/1.0/BpHwVrComposerClient.h",
         "android/dvr/composer/1.0/BsVrComposerClient.h",
-
-        "android/dvr/composer/1.0/IVrComposerView.h",
-        "android/dvr/composer/1.0/IHwVrComposerView.h",
-        "android/dvr/composer/1.0/BnHwVrComposerView.h",
-        "android/dvr/composer/1.0/BpHwVrComposerView.h",
-        "android/dvr/composer/1.0/BsVrComposerView.h",
-
-        "android/dvr/composer/1.0/IVrComposerCallback.h",
-        "android/dvr/composer/1.0/IHwVrComposerCallback.h",
-        "android/dvr/composer/1.0/BnHwVrComposerCallback.h",
-        "android/dvr/composer/1.0/BpHwVrComposerCallback.h",
-        "android/dvr/composer/1.0/BsVrComposerCallback.h",
     ],
 }
 
diff --git a/services/vr/vr_window_manager/composer/1.0/IVrComposerCallback.hal b/services/vr/vr_window_manager/composer/1.0/IVrComposerCallback.hal
deleted file mode 100644
index 6e7255e..0000000
--- a/services/vr/vr_window_manager/composer/1.0/IVrComposerCallback.hal
+++ /dev/null
@@ -1,18 +0,0 @@
-package android.dvr.composer@1.0;
-
-import android.hardware.graphics.composer@2.1::IComposerClient;
-
-interface IVrComposerCallback {
-    struct Layer {
-        handle buffer;
-        handle fence;
-        android.hardware.graphics.composer@2.1::IComposerClient.Rect display_frame;
-        android.hardware.graphics.composer@2.1::IComposerClient.FRect crop;
-        android.hardware.graphics.composer@2.1::IComposerClient.BlendMode blend_mode;
-        float alpha;
-        uint32_t type;
-        uint32_t app_id;
-    };
-
-    onNewFrame(vec<Layer> frame);
-};
diff --git a/services/vr/vr_window_manager/composer/1.0/IVrComposerView.hal b/services/vr/vr_window_manager/composer/1.0/IVrComposerView.hal
deleted file mode 100644
index e16131a..0000000
--- a/services/vr/vr_window_manager/composer/1.0/IVrComposerView.hal
+++ /dev/null
@@ -1,9 +0,0 @@
-package android.dvr.composer@1.0;
-
-import IVrComposerCallback;
-
-interface IVrComposerView {
-    registerCallback(IVrComposerCallback callback);
-
-    releaseFrame();
-};
diff --git a/services/vr/vr_window_manager/composer/Android.bp b/services/vr/vr_window_manager/composer/Android.bp
index 08c105c..7c8bb86 100644
--- a/services/vr/vr_window_manager/composer/Android.bp
+++ b/services/vr/vr_window_manager/composer/Android.bp
@@ -6,7 +6,6 @@
   name: "libvrhwc",
 
   srcs: [
-    "impl/sync_timeline.cpp",
     "impl/vr_composer_view.cpp",
     "impl/vr_hwc.cpp",
     "impl/vr_composer_client.cpp",
@@ -33,11 +32,6 @@
 
   export_include_dirs: ["."],
 
-  include_dirs: [
-    // Access to software sync timeline.
-    "system/core/libsync",
-  ],
-
   cflags: [
     "-DLOG_TAG=\"vrhwc\"",
   ],
diff --git a/services/vr/vr_window_manager/composer/impl/sync_timeline.cpp b/services/vr/vr_window_manager/composer/impl/sync_timeline.cpp
deleted file mode 100644
index e63ed26..0000000
--- a/services/vr/vr_window_manager/composer/impl/sync_timeline.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2016 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 "sync_timeline.h"
-
-#include <sys/cdefs.h>
-#include <sw_sync.h>
-#include <unistd.h>
-
-namespace android {
-namespace dvr {
-
-SyncTimeline::SyncTimeline() {}
-
-SyncTimeline::~SyncTimeline() {}
-
-bool SyncTimeline::Initialize() {
-  timeline_fd_.reset(sw_sync_timeline_create());
-  return timeline_fd_ >= 0;
-}
-
-int SyncTimeline::CreateFence(int time) {
-  return sw_sync_fence_create(timeline_fd_.get(), "dummy fence", time);
-}
-
-bool SyncTimeline::IncrementTimeline() {
-  return sw_sync_timeline_inc(timeline_fd_.get(), 1) == 0;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/vr_window_manager/composer/impl/sync_timeline.h b/services/vr/vr_window_manager/composer/impl/sync_timeline.h
deleted file mode 100644
index 945acbd..0000000
--- a/services/vr/vr_window_manager/composer/impl/sync_timeline.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2016 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 VR_WINDOW_MANAGER_COMPOSER_IMPL_SYNC_TIMELINE_H_
-#define VR_WINDOW_MANAGER_COMPOSER_IMPL_SYNC_TIMELINE_H_
-
-#include <android-base/unique_fd.h>
-
-namespace android {
-namespace dvr {
-
-// TODO(dnicoara): Remove this and move to EGL based fences.
-class SyncTimeline {
- public:
-  SyncTimeline();
-  ~SyncTimeline();
-
-  bool Initialize();
-
-  int CreateFence(int time);
-  bool IncrementTimeline();
-
- private:
-  base::unique_fd timeline_fd_;
-
-  SyncTimeline(const SyncTimeline&) = delete;
-  void operator=(const SyncTimeline&) = delete;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // VR_WINDOW_MANAGER_COMPOSER_IMPL_SYNC_TIMELINE_H_
diff --git a/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp b/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp
index 1096a37..299e8f1 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_composer_view.cpp
@@ -16,19 +16,12 @@
   composer_view_->RegisterObserver(this);
 }
 
-void VrComposerView::ReleaseFrame() {
-  LOG_ALWAYS_FATAL_IF(!composer_view_, "VrComposerView not initialized");
-  composer_view_->ReleaseFrame();
-}
-
-void VrComposerView::OnNewFrame(const ComposerView::Frame& frame) {
+base::unique_fd VrComposerView::OnNewFrame(const ComposerView::Frame& frame) {
   std::lock_guard<std::mutex> guard(mutex_);
-  if (!callback_.get()) {
-    ReleaseFrame();
-    return;
-  }
+  if (!callback_.get())
+    return base::unique_fd();
 
-  callback_->OnNewFrame(frame);
+  return callback_->OnNewFrame(frame);
 }
 
 }  // namespace dvr
diff --git a/services/vr/vr_window_manager/composer/impl/vr_composer_view.h b/services/vr/vr_window_manager/composer/impl/vr_composer_view.h
index 5a938e9..8c5ee1f 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_composer_view.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_composer_view.h
@@ -13,7 +13,7 @@
   class Callback {
    public:
     virtual ~Callback() = default;
-    virtual void OnNewFrame(const ComposerView::Frame& frame) = 0;
+    virtual base::unique_fd OnNewFrame(const ComposerView::Frame& frame) = 0;
   };
 
   VrComposerView(std::unique_ptr<Callback> callback);
@@ -21,10 +21,8 @@
 
   void Initialize(ComposerView* composer_view);
 
-  void ReleaseFrame();
-
   // ComposerView::Observer
-  void OnNewFrame(const ComposerView::Frame& frame) override;
+  base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
 
  private:
   ComposerView* composer_view_;
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
index 264ee1c..6a78c98 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.cpp
@@ -21,7 +21,6 @@
 
 #include <mutex>
 
-#include "sync_timeline.h"
 #include "vr_composer_client.h"
 
 using namespace android::hardware::graphics::common::V1_0;
@@ -86,8 +85,6 @@
 
 HwcDisplay::~HwcDisplay() {}
 
-bool HwcDisplay::Initialize() { return hwc_timeline_.Initialize(); }
-
 bool HwcDisplay::SetClientTarget(const native_handle_t* handle,
                                  base::unique_fd fence) {
   if (handle)
@@ -105,14 +102,14 @@
 
 HwcLayer* HwcDisplay::GetLayer(Layer id) {
   for (size_t i = 0; i < layers_.size(); ++i)
-    if (layers_[i].id == id) return &layers_[i];
+    if (layers_[i].info.id == id) return &layers_[i];
 
   return nullptr;
 }
 
 bool HwcDisplay::DestroyLayer(Layer id) {
   for (auto it = layers_.begin(); it != layers_.end(); ++it) {
-    if (it->id == id) {
+    if (it->info.id == id) {
       layers_.erase(it);
       return true;
     }
@@ -148,7 +145,7 @@
   for (size_t i = 0; i < layers_.size(); ++i) {
     if (i >= first_client_layer && i <= last_client_layer) {
       if (layers_[i].composition_type != IComposerClient::Composition::CLIENT) {
-        layer_ids->push_back(layers_[i].id);
+        layer_ids->push_back(layers_[i].info.id);
         types->push_back(IComposerClient::Composition::CLIENT);
         layers_[i].composition_type = IComposerClient::Composition::CLIENT;
       }
@@ -157,7 +154,7 @@
     }
 
     if (layers_[i].composition_type != IComposerClient::Composition::DEVICE) {
-      layer_ids->push_back(layers_[i].id);
+      layer_ids->push_back(layers_[i].info.id);
       types->push_back(IComposerClient::Composition::DEVICE);
       layers_[i].composition_type = IComposerClient::Composition::DEVICE;
     }
@@ -205,26 +202,18 @@
     return Error::BAD_LAYER;
   }
 
-  // Increment the time the fence is signalled every time we get the
-  // presentation frame. This ensures that calling ReleaseFrame() only affects
-  // the current frame.
-  fence_time_++;
   out_frames->swap(frame);
   return Error::NONE;
 }
 
-void HwcDisplay::GetReleaseFences(int* present_fence,
-                                  std::vector<Layer>* layer_ids,
-                                  std::vector<int>* fences) {
-  *present_fence = hwc_timeline_.CreateFence(fence_time_);
-  for (const auto& layer : layers_) {
-    layer_ids->push_back(layer.id);
-    fences->push_back(hwc_timeline_.CreateFence(fence_time_));
-  }
-}
+std::vector<Layer> HwcDisplay::UpdateLastFrameAndGetLastFrameLayers() {
+  std::vector<Layer> last_frame_layers;
+  last_frame_layers.swap(last_frame_layers_ids_);
 
-void HwcDisplay::ReleaseFrame() {
-  hwc_timeline_.IncrementTimeline();
+  for (const auto& layer : layers_)
+    last_frame_layers_ids_.push_back(layer.info.id);
+
+  return last_frame_layers;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -234,8 +223,6 @@
 
 VrHwc::~VrHwc() {}
 
-bool VrHwc::Initialize() { return display_.Initialize(); }
-
 bool VrHwc::hasCapability(Capability capability) const { return false; }
 
 void VrHwc::removeClient() {
@@ -270,7 +257,7 @@
   std::lock_guard<std::mutex> guard(mutex_);
 
   HwcLayer* layer = display_.CreateLayer();
-  *outLayer = layer->id;
+  *outLayer = layer->info.id;
   return Error::NONE;
 }
 
@@ -456,24 +443,33 @@
                             std::vector<Layer>* outLayers,
                             std::vector<int32_t>* outReleaseFences) {
   *outPresentFence = -1;
+  outLayers->clear();
+  outReleaseFences->clear();
+
   if (display != kDefaultDisplayId) {
     return Error::BAD_DISPLAY;
   }
 
   std::vector<ComposerView::ComposerLayer> frame;
-  {
-    std::lock_guard<std::mutex> guard(mutex_);
-    Error status = display_.GetFrame(&frame);
-    if (status != Error::NONE)
-      return status;
+  std::vector<Layer> last_frame_layers;
+  std::lock_guard<std::mutex> guard(mutex_);
+  Error status = display_.GetFrame(&frame);
+  if (status != Error::NONE)
+    return status;
 
-    display_.GetReleaseFences(outPresentFence, outLayers, outReleaseFences);
-  }
+  last_frame_layers = display_.UpdateLastFrameAndGetLastFrameLayers();
 
+  base::unique_fd fence;
   if (observer_)
-    observer_->OnNewFrame(frame);
-  else
-    ReleaseFrame();
+    fence = observer_->OnNewFrame(frame);
+
+  if (fence.get() < 0)
+    return Error::NONE;
+
+  *outPresentFence = dup(fence.get());
+  outLayers->swap(last_frame_layers);
+  for (size_t i = 0; i < outLayers->size(); ++i)
+    outReleaseFences->push_back(dup(fence.get()));
 
   return Error::NONE;
 }
@@ -669,11 +665,6 @@
     observer_ = nullptr;
 }
 
-void VrHwc::ReleaseFrame() {
-  std::lock_guard<std::mutex> guard(mutex_);
-  display_.ReleaseFrame();
-}
-
 ComposerView* GetComposerViewFromIComposer(
     hardware::graphics::composer::V2_1::IComposer* composer) {
   return static_cast<VrHwc*>(composer);
diff --git a/services/vr/vr_window_manager/composer/impl/vr_hwc.h b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
index 9450097..df09687 100644
--- a/services/vr/vr_window_manager/composer/impl/vr_hwc.h
+++ b/services/vr/vr_window_manager/composer/impl/vr_hwc.h
@@ -16,6 +16,7 @@
 #ifndef VR_WINDOW_MANAGER_COMPOSER_IMPL_VR_HWC_H_
 #define VR_WINDOW_MANAGER_COMPOSER_IMPL_VR_HWC_H_
 
+#include <android-base/unique_fd.h>
 #include <android/hardware/graphics/composer/2.1/IComposer.h>
 #include <ComposerBase.h>
 #include <ui/Fence.h>
@@ -24,8 +25,6 @@
 
 #include <mutex>
 
-#include "sync_timeline.h"
-
 using namespace android::hardware::graphics::common::V1_0;
 using namespace android::hardware::graphics::composer::V2_1;
 
@@ -57,6 +56,7 @@
 
     // TODO(dnicoara): Add all layer properties. For now just the basics to get
     // it going.
+    Layer id;
     sp<GraphicBuffer> buffer;
     sp<Fence> fence;
     Recti display_frame;
@@ -75,25 +75,23 @@
 
     // Returns a list of layers that need to be shown together. Layers are
     // returned in z-order, with the lowest layer first.
-    virtual void OnNewFrame(const Frame& frame) = 0;
+    virtual base::unique_fd OnNewFrame(const Frame& frame) = 0;
   };
 
   virtual ~ComposerView() {}
 
   virtual void RegisterObserver(Observer* observer) = 0;
   virtual void UnregisterObserver(Observer* observer) = 0;
-
-  // Called to release the oldest frame received by the observer.
-  virtual void ReleaseFrame() = 0;
 };
 
 struct HwcLayer {
   using Composition =
       hardware::graphics::composer::V2_1::IComposerClient::Composition;
 
-  HwcLayer(Layer new_id) : id(new_id) {}
+  HwcLayer(Layer new_id) {
+    info.id = new_id;
+  }
 
-  Layer id;
   Composition composition_type;
   uint32_t z_order;
   ComposerView::ComposerLayer info;
@@ -104,8 +102,6 @@
   HwcDisplay();
   ~HwcDisplay();
 
-  bool Initialize();
-
   HwcLayer* CreateLayer();
   bool DestroyLayer(Layer id);
   HwcLayer* GetLayer(Layer id);
@@ -118,10 +114,7 @@
 
   Error GetFrame(std::vector<ComposerView::ComposerLayer>* out_frame);
 
-  void GetReleaseFences(int* present_fence, std::vector<Layer>* layer_ids,
-                        std::vector<int>* fences);
-
-  void ReleaseFrame();
+  std::vector<Layer> UpdateLastFrameAndGetLastFrameLayers();
 
  private:
   // The client target buffer and the associated fence.
@@ -132,19 +125,11 @@
   // List of currently active layers.
   std::vector<HwcLayer> layers_;
 
+  std::vector<Layer> last_frame_layers_ids_;
+
   // Layer ID generator.
   uint64_t layer_ids_ = 1;
 
-  // Creates software sync fences used to signal releasing frames.
-  SyncTimeline hwc_timeline_;
-
-  // Keeps track of the current fence time. Used in conjunction with
-  // |hwc_timeline_| to properly signal frame release times. Allows the observer
-  // to receive multiple presentation frames without calling ReleaseFrame() in
-  // between each presentation. When the observer is ready to release a frame
-  // only the oldest presentation frame is affected by the release.
-  int fence_time_ = 0;
-
   HwcDisplay(const HwcDisplay&) = delete;
   void operator=(const HwcDisplay&) = delete;
 };
@@ -154,8 +139,6 @@
   VrHwc();
   ~VrHwc() override;
 
-  bool Initialize();
-
   bool hasCapability(Capability capability) const;
 
   Error setLayerInfo(Display display, Layer layer, uint32_t type,
@@ -246,7 +229,6 @@
   // ComposerView:
   void RegisterObserver(Observer* observer) override;
   void UnregisterObserver(Observer* observer) override;
-  void ReleaseFrame() override;
 
  private:
   wp<VrComposerClient> client_;
diff --git a/services/vr/vr_window_manager/hwc_callback.cpp b/services/vr/vr_window_manager/hwc_callback.cpp
index d3cd38c..05ec64a 100644
--- a/services/vr/vr_window_manager/hwc_callback.cpp
+++ b/services/vr/vr_window_manager/hwc_callback.cpp
@@ -38,7 +38,7 @@
 HwcCallback::~HwcCallback() {
 }
 
-void HwcCallback::OnNewFrame(const ComposerView::Frame& frame) {
+base::unique_fd HwcCallback::OnNewFrame(const ComposerView::Frame& frame) {
   std::vector<HwcLayer> hwc_frame(frame.size());
   for (size_t i = 0; i < frame.size(); ++i) {
     hwc_frame[i] = HwcLayer{
@@ -53,7 +53,8 @@
     };
   }
 
-  client_->OnFrame(std::make_unique<Frame>(std::move(hwc_frame)));
+  return client_->OnFrame(
+      std::make_unique<Frame>(std::move(hwc_frame)));
 }
 
 HwcCallback::Frame::Frame(std::vector<HwcLayer>&& layers)
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index d4d6e66..bcfeb97 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -6,6 +6,7 @@
 #include <mutex>
 #include <vector>
 
+#include <android-base/unique_fd.h>
 #include <impl/vr_composer_view.h>
 #include <impl/vr_hwc.h>
 
@@ -79,14 +80,15 @@
   class Client {
    public:
     virtual ~Client() {}
-    virtual void OnFrame(std::unique_ptr<Frame>) = 0;
+    virtual base::unique_fd OnFrame(std::unique_ptr<Frame>) = 0;
   };
 
   explicit HwcCallback(Client* client);
   ~HwcCallback() override;
 
  private:
-  void OnNewFrame(const ComposerView::Frame& frame) override;
+  base::unique_fd OnNewFrame(const ComposerView::Frame& frame) override;
+
   Client *client_;
 
   HwcCallback(const HwcCallback&) = delete;
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 84b8467..9d0aaad 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -319,10 +319,6 @@
         frame.frame->Finish() == HwcCallback::FrameStatus::kFinished) {
       current_frame_ = std::move(frame);
       pending_frames_.pop_front();
-
-      for(int i = 0; i < skipped_frame_count_ + 1; i++)
-        surface_flinger_view_->ReleaseFrame();
-      skipped_frame_count_ = 0;
     }
   }
 }
@@ -392,7 +388,7 @@
   return true;
 }
 
-void ShellView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame) {
+base::unique_fd ShellView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame) {
   ViewMode visibility =
       CalculateVisibilityFromLayerConfig(*frame.get(), current_vr_app_);
 
@@ -409,7 +405,6 @@
   pending_frames_.emplace_back(std::move(frame), visibility);
 
   if (pending_frames_.size() > kMaximumPendingFrames) {
-    skipped_frame_count_++;
     pending_frames_.pop_front();
   }
 
@@ -427,6 +422,8 @@
     QueueTask(MainThreadTask::EnteringVrMode);
     QueueTask(MainThreadTask::Show);
   }
+
+  return base::unique_fd(dup(release_fence_.get()));
 }
 
 bool ShellView::IsHit(const vec3& view_location, const vec3& view_direction,
@@ -518,6 +515,20 @@
 
     DrawIme();
   }
+
+  EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+  EGLSyncKHR sync = eglCreateSyncKHR(display, EGL_SYNC_NATIVE_FENCE_ANDROID,
+                                     nullptr);
+  if (sync != EGL_NO_SYNC_KHR) {
+    // Need to flush in order to get the fence FD.
+    glFlush();
+    base::unique_fd fence(eglDupNativeFenceFDANDROID(display, sync));
+    eglDestroySyncKHR(display, sync);
+    UpdateReleaseFence(std::move(fence));
+  } else {
+    ALOGE("Failed to create sync fence");
+    UpdateReleaseFence(base::unique_fd());
+  }
 }
 
 void ShellView::DrawIme() {
@@ -744,5 +755,10 @@
   return true;
 }
 
+void ShellView::UpdateReleaseFence(base::unique_fd fence) {
+  std::lock_guard<std::mutex> guard(pending_frame_mutex_);
+  release_fence_ = std::move(fence);
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index 39b5451..1e061bb 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -69,16 +69,15 @@
 
   void AdvanceFrame();
 
+  void UpdateReleaseFence(base::unique_fd fence);
+
   // HwcCallback::Client:
-  void OnFrame(std::unique_ptr<HwcCallback::Frame> frame) override;
+  base::unique_fd OnFrame(std::unique_ptr<HwcCallback::Frame> frame) override;
 
   std::unique_ptr<ShaderProgram> program_;
   std::unique_ptr<ShaderProgram> overlay_program_;
   std::unique_ptr<ShaderProgram> controller_program_;
 
-  // This starts at -1 so we don't call ReleaseFrame for the first frame.
-  int skipped_frame_count_ = -1;
-
   uint32_t current_vr_app_;
 
   // Used to center the scene when the shell becomes visible.
@@ -126,6 +125,8 @@
 
   mat4 controller_translate_;
 
+  base::unique_fd release_fence_;
+
   ShellView(const ShellView&) = delete;
   void operator=(const ShellView&) = delete;
 };
diff --git a/services/vr/vr_window_manager/surface_flinger_view.cpp b/services/vr/vr_window_manager/surface_flinger_view.cpp
index d42d3ff..63bc143 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.cpp
+++ b/services/vr/vr_window_manager/surface_flinger_view.cpp
@@ -84,9 +84,5 @@
   return true;
 }
 
-void SurfaceFlingerView::ReleaseFrame() {
-  vr_composer_view_->ReleaseFrame();
-}
-
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/vr_window_manager/surface_flinger_view.h b/services/vr/vr_window_manager/surface_flinger_view.h
index 9c16192..7370299 100644
--- a/services/vr/vr_window_manager/surface_flinger_view.h
+++ b/services/vr/vr_window_manager/surface_flinger_view.h
@@ -36,8 +36,6 @@
                    TextureLayer* ime_layer, bool debug,
                    bool skip_first_layer) const;
 
-  void ReleaseFrame();
-
  private:
   sp<IComposer> vr_hwcomposer_;
   std::unique_ptr<VrComposerView> vr_composer_view_;