Add FUSE node fields to support multiple nodes with same name

The following new fields are added on FUSE node:
1. transforms: Flags determining what, if any transformations should
be done to the node
2. io_path: Allows re-directing path to use for actual IO different
from node->BuildPath()
3. io_ready: Allows lazyily transforming a node before accessing the
new io_path

These fields have default values and change should be a no-op

Test: Manual && fsstress for ~24hrs
Bug: 158466177
Change-Id: I93417795b4b3d8b97e61385e4a24e45e562d3382
diff --git a/jni/FuseDaemon.cpp b/jni/FuseDaemon.cpp
index d40e0a6..c332bc505 100644
--- a/jni/FuseDaemon.cpp
+++ b/jni/FuseDaemon.cpp
@@ -412,9 +412,13 @@
     }
 
     bool should_inval = false;
+    bool transforms_complete = true;
+    int transforms = 0;
+    string io_path;
     node = parent->LookupChildByName(name, true /* acquire */);
     if (!node) {
-        node = ::node::Create(parent, name, &fuse->lock, &fuse->tracker);
+        node = ::node::Create(parent, name, io_path, transforms_complete, transforms, &fuse->lock,
+                              &fuse->tracker);
     } else if (!mediaprovider::fuse::containsMount(path, std::to_string(getuid() / PER_USER_RANGE))) {
         should_inval = node->HasCaseInsensitiveMatch();
         // Only invalidate a path if it does not contain mount.
diff --git a/jni/node-inl.h b/jni/node-inl.h
index 13df5a3..e5344cc 100644
--- a/jni/node-inl.h
+++ b/jni/node-inl.h
@@ -19,6 +19,7 @@
 
 #include <android-base/logging.h>
 
+#include <atomic>
 #include <cstdint>
 #include <limits>
 #include <list>
@@ -114,13 +115,14 @@
 class node {
   public:
     // Creates a new node with the specified parent, name and lock.
-    static node* Create(node* parent, const std::string& name, std::recursive_mutex* lock,
+    static node* Create(node* parent, const std::string& name, const std::string& io_path,
+                        bool transforms_complete, const int transforms, std::recursive_mutex* lock,
                         NodeTracker* tracker) {
         // Place the entire constructor under a critical section to make sure
         // node creation, tracking (if enabled) and the addition to a parent are
         // atomic.
         std::lock_guard<std::recursive_mutex> guard(*lock);
-        return new node(parent, name, lock, tracker);
+        return new node(parent, name, io_path, transforms_complete, transforms, lock, tracker);
     }
 
     // Creates a new root node. Root nodes have no parents by definition
@@ -128,7 +130,7 @@
     static node* CreateRoot(const std::string& path, std::recursive_mutex* lock,
                             NodeTracker* tracker) {
         std::lock_guard<std::recursive_mutex> guard(*lock);
-        node* root = new node(nullptr, path, lock, tracker);
+        node* root = new node(nullptr, path, path, true, 0, lock, tracker);
 
         // The root always has one extra reference to avoid it being
         // accidentally collected.
@@ -176,12 +178,15 @@
 
     // Looks up a direct descendant of this node by name. If |acquire| is true,
     // also Acquire the node before returning a reference to it.
-    node* LookupChildByName(const std::string& name, bool acquire) const {
-        return ForChild(name, [acquire](node* child) {
-            if (acquire) {
-                child->Acquire();
+    node* LookupChildByName(const std::string& name, bool acquire, const int transforms = 0) const {
+        return ForChild(name, [acquire, transforms](node* child) {
+            if (child->transforms_ == transforms) {
+                if (acquire) {
+                    child->Acquire();
+                }
+                return true;
             }
-            return true;
+            return false;
         });
     }
 
@@ -253,6 +258,16 @@
         return name_;
     }
 
+    const std::string& GetIoPath() const { return io_path_; }
+
+    int GetTransforms() const { return transforms_; }
+
+    bool IsTransformsComplete() const {
+        return transforms_complete_.load(std::memory_order_acquire);
+    }
+
+    void SetTransformsComplete() { transforms_complete_.store(true, std::memory_order_release); }
+
     node* GetParent() const {
         std::lock_guard<std::recursive_mutex> guard(*lock_);
         return parent_;
@@ -326,8 +341,12 @@
     static const node* LookupAbsolutePath(const node* root, const std::string& absolute_path);
 
   private:
-    node(node* parent, const std::string& name, std::recursive_mutex* lock, NodeTracker* tracker)
+    node(node* parent, const std::string& name, const std::string& io_path, bool transforms_complete,
+         const int transforms, std::recursive_mutex* lock, NodeTracker* tracker)
         : name_(name),
+          io_path_(io_path),
+          transforms_complete_(transforms_complete),
+          transforms_(transforms),
           refcount_(0),
           parent_(nullptr),
           has_redacted_cache_(false),
@@ -454,6 +473,15 @@
 
     // The name of this node. Non-const because it can change during renames.
     std::string name_;
+    // Filesystem path that will be used for IO (if it is non-empty) instead of node->BuildPath
+    const std::string io_path_;
+    // Whether any transforms required on |io_path_| are complete.
+    // If false, might need to call a node transform function with |transforms| below
+    std::atomic_bool transforms_complete_;
+    // Opaque flags that determine the 'supported' and 'required' transforms to perform on node
+    // before IO. These flags should not be interpreted in native but should be passed as part
+    // of a transform function and if successful, |transforms_complete_| should be set to true
+    const int transforms_;
     // The reference count for this node. Guarded by |lock_|.
     uint32_t refcount_;
     // Set of children of this node. All of them contain a back reference
diff --git a/jni/node_test.cpp b/jni/node_test.cpp
index 90f0894..d2ba399 100644
--- a/jni/node_test.cpp
+++ b/jni/node_test.cpp
@@ -31,8 +31,9 @@
 
     typedef std::unique_ptr<node, decltype(&NodeTest::destroy)> unique_node_ptr;
 
-    unique_node_ptr CreateNode(node* parent, const std::string& path) {
-        return unique_node_ptr(node::Create(parent, path, &lock_, &tracker_), &NodeTest::destroy);
+    unique_node_ptr CreateNode(node* parent, const std::string& path, const int transforms = 0) {
+        return unique_node_ptr(node::Create(parent, path, "", true, transforms, &lock_, &tracker_),
+                               &NodeTest::destroy);
     }
 
     static class node* ForChild(class node* node, const std::string& name,
@@ -66,7 +67,7 @@
 }
 
 TEST_F(NodeTest, TestRelease) {
-    node* node = node::Create(nullptr, "/path", &lock_, &tracker_);
+    node* node = node::Create(nullptr, "/path", "", true, 0, &lock_, &tracker_);
     acquire(node);
     acquire(node);
     ASSERT_EQ(3, GetRefCount(node));
@@ -141,57 +142,96 @@
 TEST_F(NodeTest, TestRenameNameForChild) {
     unique_node_ptr parent = CreateNode(nullptr, "/path");
 
-    unique_node_ptr child = CreateNode(parent.get(), "subdir");
-    ASSERT_EQ(2, GetRefCount(parent.get()));
-    ASSERT_EQ(child.get(), parent->LookupChildByName("subdir", false /* acquire */));
+    unique_node_ptr child0 = CreateNode(parent.get(), "subdir", 0 /* transforms */);
+    unique_node_ptr child1 = CreateNode(parent.get(), "subdir", 1 /* transforms */);
+    ASSERT_EQ(3, GetRefCount(parent.get()));
+    ASSERT_EQ(child0.get(),
+              parent->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(child1.get(),
+              parent->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
 
     parent->RenameChild("subdir", "subdir_new", parent.get());
 
-    ASSERT_EQ(2, GetRefCount(parent.get()));
-    ASSERT_EQ(nullptr, parent->LookupChildByName("subdir", false /* acquire */));
-    ASSERT_EQ(child.get(), parent->LookupChildByName("subdir_new", false /* acquire */));
+    ASSERT_EQ(3, GetRefCount(parent.get()));
+    ASSERT_EQ(nullptr,
+              parent->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(nullptr,
+              parent->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+    ASSERT_EQ(child0.get(),
+              parent->LookupChildByName("subdir_new", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(child1.get(),
+              parent->LookupChildByName("subdir_new", false /* acquire */, 1 /* transforms */));
 
-    ASSERT_EQ("/path/subdir_new", child->BuildPath());
-    ASSERT_EQ(1, GetRefCount(child.get()));
+    ASSERT_EQ("/path/subdir_new", child0->BuildPath());
+    ASSERT_EQ("/path/subdir_new", child1->BuildPath());
+    ASSERT_EQ(1, GetRefCount(child0.get()));
+    ASSERT_EQ(1, GetRefCount(child1.get()));
 }
 
 TEST_F(NodeTest, TestRenameParentForChild) {
     unique_node_ptr parent1 = CreateNode(nullptr, "/path1");
     unique_node_ptr parent2 = CreateNode(nullptr, "/path2");
 
-    unique_node_ptr child = CreateNode(parent1.get(), "subdir");
-    ASSERT_EQ(2, GetRefCount(parent1.get()));
-    ASSERT_EQ(child.get(), parent1->LookupChildByName("subdir", false /* acquire */));
+    unique_node_ptr child0 = CreateNode(parent1.get(), "subdir", 0 /* transforms */);
+    unique_node_ptr child1 = CreateNode(parent1.get(), "subdir", 1 /* transforms */);
+    ASSERT_EQ(3, GetRefCount(parent1.get()));
+    ASSERT_EQ(child0.get(),
+              parent1->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(child1.get(),
+              parent1->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
 
     parent1->RenameChild("subdir", "subdir", parent2.get());
     ASSERT_EQ(1, GetRefCount(parent1.get()));
-    ASSERT_EQ(nullptr, parent1->LookupChildByName("subdir", false /* acquire */));
+    ASSERT_EQ(nullptr,
+              parent1->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(nullptr,
+              parent1->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
 
-    ASSERT_EQ(2, GetRefCount(parent2.get()));
-    ASSERT_EQ(child.get(), parent2->LookupChildByName("subdir", false /* acquire */));
+    ASSERT_EQ(3, GetRefCount(parent2.get()));
+    ASSERT_EQ(child0.get(),
+              parent2->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(child1.get(),
+              parent2->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
 
-    ASSERT_EQ("/path2/subdir", child->BuildPath());
-    ASSERT_EQ(1, GetRefCount(child.get()));
+    ASSERT_EQ("/path2/subdir", child0->BuildPath());
+    ASSERT_EQ("/path2/subdir", child1->BuildPath());
+    ASSERT_EQ(1, GetRefCount(child0.get()));
+    ASSERT_EQ(1, GetRefCount(child1.get()));
 }
 
 TEST_F(NodeTest, TestRenameNameAndParentForChild) {
     unique_node_ptr parent1 = CreateNode(nullptr, "/path1");
     unique_node_ptr parent2 = CreateNode(nullptr, "/path2");
 
-    unique_node_ptr child = CreateNode(parent1.get(), "subdir");
-    ASSERT_EQ(2, GetRefCount(parent1.get()));
-    ASSERT_EQ(child.get(), parent1->LookupChildByName("subdir", false /* acquire */));
+    unique_node_ptr child0 = CreateNode(parent1.get(), "subdir", 0 /* transforms */);
+    unique_node_ptr child1 = CreateNode(parent1.get(), "subdir", 1 /* transforms */);
+    ASSERT_EQ(3, GetRefCount(parent1.get()));
+    ASSERT_EQ(child0.get(),
+              parent1->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(child1.get(),
+              parent1->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
 
     parent1->RenameChild("subdir", "subdir_new", parent2.get());
     ASSERT_EQ(1, GetRefCount(parent1.get()));
-    ASSERT_EQ(nullptr, parent1->LookupChildByName("subdir", false /* acquire */));
-    ASSERT_EQ(nullptr, parent1->LookupChildByName("subdir_new", false /* acquire */));
+    ASSERT_EQ(nullptr,
+              parent1->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(nullptr,
+              parent1->LookupChildByName("subdir_new", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(nullptr,
+              parent1->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+    ASSERT_EQ(nullptr,
+              parent1->LookupChildByName("subdir_new", false /* acquire */, 1 /* transforms */));
 
-    ASSERT_EQ(2, GetRefCount(parent2.get()));
-    ASSERT_EQ(child.get(), parent2->LookupChildByName("subdir_new", false /* acquire */));
+    ASSERT_EQ(3, GetRefCount(parent2.get()));
+    ASSERT_EQ(nullptr,
+              parent1->LookupChildByName("subdir_new", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(nullptr,
+              parent1->LookupChildByName("subdir_new", false /* acquire */, 1 /* transforms */));
 
-    ASSERT_EQ("/path2/subdir_new", child->BuildPath());
-    ASSERT_EQ(1, GetRefCount(child.get()));
+    ASSERT_EQ("/path2/subdir_new", child0->BuildPath());
+    ASSERT_EQ("/path2/subdir_new", child1->BuildPath());
+    ASSERT_EQ(1, GetRefCount(child0.get()));
+    ASSERT_EQ(1, GetRefCount(child1.get()));
 }
 
 TEST_F(NodeTest, TestBuildPath) {
@@ -219,21 +259,28 @@
 
 TEST_F(NodeTest, TestSetDeletedForChild) {
     unique_node_ptr parent = CreateNode(nullptr, "/path");
-    unique_node_ptr child = CreateNode(parent.get(), "subdir");
+    unique_node_ptr child0 = CreateNode(parent.get(), "subdir", 0 /* transforms */);
+    unique_node_ptr child1 = CreateNode(parent.get(), "subdir", 1 /* transforms */);
 
-    ASSERT_EQ(child.get(), parent->LookupChildByName("subdir", false /* acquire */));
+    ASSERT_EQ(child0.get(),
+              parent->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(child1.get(),
+              parent->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
     parent->SetDeletedForChild("subdir");
-    ASSERT_EQ(nullptr, parent->LookupChildByName("subdir", false /* acquire */));
+    ASSERT_EQ(nullptr,
+              parent->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(nullptr,
+              parent->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
 }
 
 TEST_F(NodeTest, DeleteTree) {
     unique_node_ptr parent = CreateNode(nullptr, "/path");
 
     // This is the tree that we intend to delete.
-    node* child = node::Create(parent.get(), "subdir", &lock_, &tracker_);
-    node::Create(child, "s1", &lock_, &tracker_);
-    node* subchild2 = node::Create(child, "s2", &lock_, &tracker_);
-    node::Create(subchild2, "sc2", &lock_, &tracker_);
+    node* child = node::Create(parent.get(), "subdir", "", true, 0, &lock_, &tracker_);
+    node::Create(child, "s1", "", true, 0, &lock_, &tracker_);
+    node* subchild2 = node::Create(child, "s2", "", true, 0, &lock_, &tracker_);
+    node::Create(subchild2, "sc2", "", true, 0, &lock_, &tracker_);
 
     ASSERT_EQ(child, parent->LookupChildByName("subdir", false /* acquire */));
     node::DeleteTree(child);
@@ -248,6 +295,20 @@
     ASSERT_EQ(nullptr, parent->LookupChildByName("", false /* acquire */));
 }
 
+TEST_F(NodeTest, LookupChildByName_transforms) {
+    unique_node_ptr parent = CreateNode(nullptr, "/path");
+    unique_node_ptr child0 = CreateNode(parent.get(), "subdir", 0 /* transforms */);
+    unique_node_ptr child1 = CreateNode(parent.get(), "subdir", 1 /* transforms */);
+
+    ASSERT_EQ(child0.get(), parent->LookupChildByName("subdir", false /* acquire */));
+    ASSERT_EQ(child0.get(),
+              parent->LookupChildByName("subdir", false /* acquire */, 0 /* transforms */));
+    ASSERT_EQ(child1.get(),
+              parent->LookupChildByName("subdir", false /* acquire */, 1 /* transforms */));
+    ASSERT_EQ(nullptr,
+              parent->LookupChildByName("subdir", false /* acquire */, 2 /* transforms */));
+}
+
 TEST_F(NodeTest, LookupChildByName_refcounts) {
     unique_node_ptr parent = CreateNode(nullptr, "/path");
     unique_node_ptr child = CreateNode(parent.get(), "subdir");