Port the current code to new IncFS

Bug: 146080380
Test: manual, "cmd incremental install-start"

Change-Id: I6761c3f0e58b6d4de1ae3c4b31c23204fba9f740
diff --git a/Android.bp b/Android.bp
index 9411eec..627681c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -922,6 +922,8 @@
     srcs: [
         "core/java/android/os/incremental/IIncrementalManager.aidl",
         "core/java/android/os/incremental/IIncrementalManagerNative.aidl",
+        "core/java/android/os/incremental/IncrementalNewFileParams.aidl",
+        "core/java/android/os/incremental/IncrementalSignature.aidl",
     ],
     path: "core/java",
 }
diff --git a/core/java/android/os/incremental/IIncrementalManager.aidl b/core/java/android/os/incremental/IIncrementalManager.aidl
index 17a310a..b415bc0 100644
--- a/core/java/android/os/incremental/IIncrementalManager.aidl
+++ b/core/java/android/os/incremental/IIncrementalManager.aidl
@@ -33,5 +33,7 @@
     boolean startDataLoader(int mountId);
     void showHealthBlockedUI(int mountId);
     void destroyDataLoader(int mountId);
-    void newFileForDataLoader(int mountId, long inode, in byte[] metadata);
+
+    // fileId is a 16 byte long identifier.
+    void newFileForDataLoader(int mountId, in byte[] fileId, in byte[] metadata);
 }
diff --git a/core/java/android/os/incremental/IIncrementalManagerNative.aidl b/core/java/android/os/incremental/IIncrementalManagerNative.aidl
index 14215b1..2b6cd14 100644
--- a/core/java/android/os/incremental/IIncrementalManagerNative.aidl
+++ b/core/java/android/os/incremental/IIncrementalManagerNative.aidl
@@ -17,6 +17,7 @@
 package android.os.incremental;
 
 import android.content.pm.DataLoaderParamsParcel;
+import android.os.incremental.IncrementalNewFileParams;
 
 /** @hide */
 interface IIncrementalManagerNative {
@@ -40,7 +41,7 @@
      */
     const int BIND_TEMPORARY = 0;
     const int BIND_PERMANENT = 1;
-    int makeBindMount(int storageId, in @utf8InCpp String pathUnderStorage, in @utf8InCpp String targetFullPath, int bindType);
+    int makeBindMount(int storageId, in @utf8InCpp String sourcePath, in @utf8InCpp String targetFullPath, int bindType);
 
     /**
      * Deletes an existing bind mount on a path under a storage. Returns 0 on success, and -errno on failure.
@@ -48,49 +49,50 @@
     int deleteBindMount(int storageId, in @utf8InCpp String targetFullPath);
 
     /**
-     * Creates a directory under a storage. The target directory is specified by its relative path under the storage.
+     * Creates a directory under a storage. The target directory is specified by its path.
      */
-    int makeDirectory(int storageId, in @utf8InCpp String pathUnderStorage);
+    int makeDirectory(int storageId, in @utf8InCpp String path);
 
     /**
-     * Recursively creates a directory under a storage. The target directory is specified by its relative path under the storage.
+     * Recursively creates a directory under a storage. The target directory is specified by its path.
      * All the parent directories of the target directory will be created if they do not exist already.
      */
-    int makeDirectories(int storageId, in @utf8InCpp String pathUnderStorage);
+    int makeDirectories(int storageId, in @utf8InCpp String path);
 
     /**
-     * Creates a file under a storage, specifying its name, size and metadata.
+     * Creates a file under a storage.
      */
-    int makeFile(int storageId, in @utf8InCpp String pathUnderStorage, long size, in byte[] metadata);
+    int makeFile(int storageId, in @utf8InCpp String path, in IncrementalNewFileParams params);
 
     /**
      * Creates a file under a storage. Content of the file is from a range inside another file.
-     * Both files are specified by relative paths under storage.
+     * Both files are specified by their paths.
      */
-    int makeFileFromRange(int storageId, in @utf8InCpp String targetPathUnderStorage, in @utf8InCpp String sourcePathUnderStorage, long start, long end);
+    int makeFileFromRange(int storageId, in @utf8InCpp String targetPath, in @utf8InCpp String sourcePath, long start, long end);
 
     /**
      * Creates a hard link between two files in two storage instances.
-     * Source and dest specified by parent storage IDs and their relative paths under the storage.
+     * Source and dest specified by parent storage IDs and their paths.
      * The source and dest storage instances should be in the same fs mount.
      * Note: destStorageId can be the same as sourceStorageId.
      */
-    int makeLink(int sourceStorageId, in @utf8InCpp String sourcePathUnderStorage, int destStorageId, in @utf8InCpp String destPathUnderStorage);
+    int makeLink(int sourceStorageId, in @utf8InCpp String sourcePath, int destStorageId, in @utf8InCpp String destPath);
 
     /**
-     * Deletes a hard link in a storage, specified by the relative path of the link target under storage.
+     * Deletes a hard link in a storage, specified by its path.
      */
-    int unlink(int storageId, in @utf8InCpp String pathUnderStorage);
+    int unlink(int storageId, in @utf8InCpp String path);
 
     /**
-     * Checks if a file's certain range is loaded. File is specified by relative file path under storage.
+     * Checks if a file's certain range is loaded. File is specified by its path.
      */
-    boolean isFileRangeLoaded(int storageId, in @utf8InCpp String pathUnderStorage, long start, long end);
+    boolean isFileRangeLoaded(int storageId, in @utf8InCpp String path, long start, long end);
 
     /**
-     * Reads the metadata of a file. File is specified by relative path under storage.
+     * Reads the metadata of a file. File is specified by either its path or 16 byte id.
      */
-    byte[] getFileMetadata(int storageId, in @utf8InCpp String pathUnderStorage);
+    byte[] getMetadataByPath(int storageId, in @utf8InCpp String path);
+    byte[] getMetadataById(int storageId, in byte[] fileId);
 
     /**
      * Starts loading data for a storage.
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 63335a0..a0bfc1b 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -134,8 +134,8 @@
         }
 
         if (!new File(mDefaultDir, apk.getName()).exists()) {
-            mDefaultStorage.makeFile(apk.getName(), apk.getSize(),
-                    apk.getMetadata());
+            mDefaultStorage.makeFile(apk.getName(), apk.getSize(), null,
+                    apk.getMetadata(), 0, null, null, null);
         }
         // Assuming APK files are already named properly, e.g., "base.apk"
         mDefaultStorage.makeLink(apk.getName(), mApkStorage, apk.getName());
@@ -167,7 +167,8 @@
             current += '/';
         }
         String libFilePath = current + Paths.get(lib.getName()).getFileName();
-        mDefaultStorage.makeFile(libFilePath, lib.getSize(), lib.getMetadata());
+        mDefaultStorage.makeFile(libFilePath, lib.getSize(), null, lib.getMetadata(), 0, null, null,
+                                 null);
         mDefaultStorage.makeLink(libFilePath, mApkStorage, libFilePath);
     }
 
@@ -183,7 +184,8 @@
                     IncrementalManager.CREATE_MODE_CREATE
                             | IncrementalManager.CREATE_MODE_TEMPORARY_BIND);
         }
-        mDefaultStorage.makeFile(obb.getName(), obb.getSize(), obb.getMetadata());
+        mDefaultStorage.makeFile(obb.getName(), obb.getSize(), null, obb.getMetadata(), 0, null,
+                                 null, null);
         mDefaultStorage.makeLink(obb.getName(), mObbStorage, obb.getName());
     }
 
diff --git a/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl b/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl
index 0ae353d..6018ad1 100644
--- a/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl
+++ b/core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl
@@ -17,11 +17,12 @@
 package android.os.incremental;
 
 /**
- * Wraps two file descriptors that Incremental Service uses to communicate
+ * Wraps the file descriptors Incremental Service uses to communicate
  * with Incremental FileSystem.
  * @hide
  */
 parcelable IncrementalFileSystemControlParcel {
-    @nullable ParcelFileDescriptor cmd;
-    @nullable ParcelFileDescriptor log;
+    ParcelFileDescriptor cmd;
+    ParcelFileDescriptor pendingReads;
+    ParcelFileDescriptor log;
 }
diff --git a/core/java/android/os/incremental/IncrementalNewFileParams.aidl b/core/java/android/os/incremental/IncrementalNewFileParams.aidl
new file mode 100644
index 0000000..182732c
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalNewFileParams.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.os.incremental;
+
+import android.os.incremental.IncrementalSignature;
+
+/**
+ * All the parameters to create a new file on IncFS
+ * FileId is a 16 byte-long identifier.
+ * @hide
+ */
+parcelable IncrementalNewFileParams {
+    long size;
+    byte[] fileId;
+    byte[] metadata;
+    @nullable IncrementalSignature signature;
+}
diff --git a/core/java/android/os/incremental/IncrementalSignature.aidl b/core/java/android/os/incremental/IncrementalSignature.aidl
new file mode 100644
index 0000000..729e8e5
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalSignature.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package android.os.incremental;
+
+/** {@hide} */
+parcelable IncrementalSignature {
+    /*
+     * Stable AIDL doesn't support constants, but here's the possible values
+     *   const int HASH_ALGO_NONE = 0;
+     *   const int HASH_ALGO_SHA256 = 1;
+    */
+
+    int hashAlgorithm = 0;
+    byte[] rootHash;
+    byte[] additionalData;
+    byte[] signature;
+}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index 2750868..91dda08 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -22,6 +22,8 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.UUID;
 
 /**
  * Provides operations on an Incremental File System directory, using IncrementalServiceNative.
@@ -64,14 +66,14 @@
      * Temporarily bind-mounts a subdir under the current storage directory to a target directory.
      * The bind-mount will NOT be preserved between device reboots.
      *
-     * @param sourcePathUnderStorage Source path as a relative path under current storage
-     *                               directory.
-     * @param targetPath             Absolute path to the target directory.
+     * @param sourcePath Source path as a relative path under current storage
+     *                   directory.
+     * @param targetPath Absolute path to the target directory.
      */
-    public void bind(@NonNull String sourcePathUnderStorage, @NonNull String targetPath)
+    public void bind(@NonNull String sourcePath, @NonNull String targetPath)
             throws IOException {
         try {
-            int res = mService.makeBindMount(mId, sourcePathUnderStorage, targetPath,
+            int res = mService.makeBindMount(mId, sourcePath, targetPath,
                     IIncrementalManagerNative.BIND_TEMPORARY);
             if (res < 0) {
                 throw new IOException("bind() failed with errno " + -res);
@@ -96,13 +98,13 @@
      * Permanently bind-mounts a subdir under the current storage directory to a target directory.
      * The bind-mount WILL be preserved between device reboots.
      *
-     * @param sourcePathUnderStorage Relative path under the current storage directory.
-     * @param targetPath             Absolute path to the target directory.
+     * @param sourcePath Relative path under the current storage directory.
+     * @param targetPath Absolute path to the target directory.
      */
-    public void bindPermanent(@NonNull String sourcePathUnderStorage, @NonNull String targetPath)
+    public void bindPermanent(@NonNull String sourcePath, @NonNull String targetPath)
             throws IOException {
         try {
-            int res = mService.makeBindMount(mId, sourcePathUnderStorage, targetPath,
+            int res = mService.makeBindMount(mId, sourcePath, targetPath,
                     IIncrementalManagerNative.BIND_PERMANENT);
             if (res < 0) {
                 throw new IOException("bind() permanent failed with errno " + -res);
@@ -131,11 +133,11 @@
     /**
      * Creates a sub-directory under the current storage directory.
      *
-     * @param pathUnderStorage Relative path of the sub-directory, e.g., "subdir"
+     * @param path Relative path of the sub-directory, e.g., "subdir"
      */
-    public void makeDirectory(@NonNull String pathUnderStorage) throws IOException {
+    public void makeDirectory(@NonNull String path) throws IOException {
         try {
-            int res = mService.makeDirectory(mId, pathUnderStorage);
+            int res = mService.makeDirectory(mId, path);
             if (res < 0) {
                 throw new IOException("makeDirectory() failed with errno " + -res);
             }
@@ -148,11 +150,11 @@
      * Creates a sub-directory under the current storage directory. If its parent dirs do not exist,
      * create the parent dirs as well.
      *
-     * @param pathUnderStorage Relative path of the sub-directory, e.g., "subdir/subsubdir"
+     * @param path Full path.
      */
-    public void makeDirectories(@NonNull String pathUnderStorage) throws IOException {
+    public void makeDirectories(@NonNull String path) throws IOException {
         try {
-            int res = mService.makeDirectories(mId, pathUnderStorage);
+            int res = mService.makeDirectories(mId, path);
             if (res < 0) {
                 throw new IOException("makeDirectory() failed with errno " + -res);
             }
@@ -164,15 +166,27 @@
     /**
      * Creates a file under the current storage directory.
      *
-     * @param pathUnderStorage Relative path of the new file.
+     * @param path             Relative path of the new file.
      * @param size             Size of the new file in bytes.
      * @param metadata         Metadata bytes.
      */
-    public void makeFile(@NonNull String pathUnderStorage, long size,
-            @Nullable byte[] metadata) throws IOException {
+    public void makeFile(@NonNull String path, long size, @Nullable UUID id,
+            @Nullable byte[] metadata, int hashAlgorithm, @Nullable byte[] rootHash,
+            @Nullable byte[] additionalData, @Nullable byte[] signature) throws IOException {
         try {
-            int res = mService.makeFile(mId, pathUnderStorage, size, metadata);
-            if (res < 0) {
+            final IncrementalNewFileParams params = new IncrementalNewFileParams();
+            params.size = size;
+            params.metadata = metadata;
+            params.fileId = idToBytes(id);
+            if (hashAlgorithm != 0 || signature != null) {
+                params.signature = new IncrementalSignature();
+                params.signature.hashAlgorithm = hashAlgorithm;
+                params.signature.rootHash = rootHash;
+                params.signature.additionalData = additionalData;
+                params.signature.signature = signature;
+            }
+            int res = mService.makeFile(mId, path, params);
+            if (res != 0) {
                 throw new IOException("makeFile() failed with errno " + -res);
             }
         } catch (RemoteException e) {
@@ -184,15 +198,15 @@
      * Creates a file in Incremental storage. The content of the file is mapped from a range inside
      * a source file in the same storage.
      *
-     * @param destRelativePath   Target relative path under storage.
-     * @param sourceRelativePath Source relative path under storage.
+     * @param destPath           Target full path.
+     * @param sourcePath         Source full path.
      * @param rangeStart         Starting offset (in bytes) in the source file.
      * @param rangeEnd           Ending offset (in bytes) in the source file.
      */
-    public void makeFileFromRange(@NonNull String destRelativePath,
-            @NonNull String sourceRelativePath, long rangeStart, long rangeEnd) throws IOException {
+    public void makeFileFromRange(@NonNull String destPath,
+            @NonNull String sourcePath, long rangeStart, long rangeEnd) throws IOException {
         try {
-            int res = mService.makeFileFromRange(mId, destRelativePath, sourceRelativePath,
+            int res = mService.makeFileFromRange(mId, destPath, sourcePath,
                     rangeStart, rangeEnd);
             if (res < 0) {
                 throw new IOException("makeFileFromRange() failed, errno " + -res);
@@ -206,15 +220,15 @@
      * Creates a hard-link between two paths, which can be under different storages but in the same
      * Incremental File System.
      *
-     * @param sourcePathUnderStorage The relative path of the source.
-     * @param destStorage            The target storage of the link target.
-     * @param destPathUnderStorage   The relative path of the target.
+     * @param sourcePath    The absolute path of the source.
+     * @param destStorage   The target storage of the link target.
+     * @param destPath      The absolute path of the target.
      */
-    public void makeLink(@NonNull String sourcePathUnderStorage, IncrementalStorage destStorage,
-            @NonNull String destPathUnderStorage) throws IOException {
+    public void makeLink(@NonNull String sourcePath, IncrementalStorage destStorage,
+            @NonNull String destPath) throws IOException {
         try {
-            int res = mService.makeLink(mId, sourcePathUnderStorage, destStorage.getId(),
-                    destPathUnderStorage);
+            int res = mService.makeLink(mId, sourcePath, destStorage.getId(),
+                    destPath);
             if (res < 0) {
                 throw new IOException("makeLink() failed with errno " + -res);
             }
@@ -226,11 +240,11 @@
     /**
      * Deletes a hard-link under the current storage directory.
      *
-     * @param pathUnderStorage The relative path of the target.
+     * @param path The absolute path of the target.
      */
-    public void unlink(@NonNull String pathUnderStorage) throws IOException {
+    public void unlink(@NonNull String path) throws IOException {
         try {
-            int res = mService.unlink(mId, pathUnderStorage);
+            int res = mService.unlink(mId, path);
             if (res < 0) {
                 throw new IOException("unlink() failed with errno " + -res);
             }
@@ -242,13 +256,14 @@
     /**
      * Rename an old file name to a new file name under the current storage directory.
      *
-     * @param sourcePathUnderStorage Old file path as a relative path to the storage directory.
-     * @param destPathUnderStorage   New file path as a relative path to the storage directory.
+     * @param sourcepath Old file path as a full path to the storage directory.
+     * @param destpath   New file path as a full path to the storage directory.
      */
-    public void moveFile(@NonNull String sourcePathUnderStorage,
-            @NonNull String destPathUnderStorage) throws IOException {
+    public void moveFile(@NonNull String sourcepath,
+            @NonNull String destpath) throws IOException {
+        //TODO(zyy): implement using rename(2) when confirmed that IncFS supports it.
         try {
-            int res = mService.makeLink(mId, sourcePathUnderStorage, mId, destPathUnderStorage);
+            int res = mService.makeLink(mId, sourcepath, mId, destpath);
             if (res < 0) {
                 throw new IOException("moveFile() failed at makeLink(), errno " + -res);
             }
@@ -256,7 +271,7 @@
             e.rethrowFromSystemServer();
         }
         try {
-            mService.unlink(mId, sourcePathUnderStorage);
+            mService.unlink(mId, sourcepath);
         } catch (RemoteException ignored) {
         }
     }
@@ -274,7 +289,7 @@
             throw new IOException("moveDir() requires that destination dir already exists.");
         }
         try {
-            int res = mService.makeBindMount(mId, "", destPath,
+            int res = mService.makeBindMount(mId, sourcePath, destPath,
                     IIncrementalManagerNative.BIND_PERMANENT);
             if (res < 0) {
                 throw new IOException("moveDir() failed at making bind mount, errno " + -res);
@@ -291,24 +306,24 @@
     /**
      * Checks whether a file under the current storage directory is fully loaded.
      *
-     * @param pathUnderStorage The relative path of the file.
+     * @param path The relative path of the file.
      * @return True if the file is fully loaded.
      */
-    public boolean isFileFullyLoaded(@NonNull String pathUnderStorage) {
-        return isFileRangeLoaded(pathUnderStorage, 0, -1);
+    public boolean isFileFullyLoaded(@NonNull String path) {
+        return isFileRangeLoaded(path, 0, -1);
     }
 
     /**
      * Checks whether a range in a file if loaded.
      *
-     * @param pathUnderStorage The relative path of the file.
+     * @param path The relative path of the file.
      * @param start            The starting offset of the range.
      * @param end              The ending offset of the range.
      * @return True if the file is fully loaded.
      */
-    public boolean isFileRangeLoaded(@NonNull String pathUnderStorage, long start, long end) {
+    public boolean isFileRangeLoaded(@NonNull String path, long start, long end) {
         try {
-            return mService.isFileRangeLoaded(mId, pathUnderStorage, start, end);
+            return mService.isFileRangeLoaded(mId, path, start, end);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
             return false;
@@ -318,13 +333,65 @@
     /**
      * Returns the metadata object of an IncFs File.
      *
-     * @param pathUnderStorage The relative path of the file.
+     * @param path The relative path of the file.
      * @return Byte array that contains metadata bytes.
      */
     @Nullable
-    public byte[] getFileMetadata(@NonNull String pathUnderStorage) {
+    public byte[] getFileMetadata(@NonNull String path) {
         try {
-            return mService.getFileMetadata(mId, pathUnderStorage);
+            return mService.getMetadataByPath(mId, path);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+            return null;
+        }
+    }
+
+    private static final int UUID_BYTE_SIZE = 16;
+
+    /**
+     * Converts UUID to a byte array usable for Incremental API calls
+     *
+     * @param id The id to convert
+     * @return Byte array that contains the same ID.
+     */
+    public static byte[] idToBytes(UUID id) {
+        if (id == null) {
+            return null;
+        }
+        final ByteBuffer buf = ByteBuffer.wrap(new byte[UUID_BYTE_SIZE]);
+        buf.putLong(id.getMostSignificantBits());
+        buf.putLong(id.getLeastSignificantBits());
+        return buf.array();
+    }
+
+    /**
+     * Converts UUID from a byte array usable for Incremental API calls
+     *
+     * @param bytes The id in byte array format, 16 bytes long
+     * @return UUID constructed from the byte array.
+     */
+    public static UUID bytesToId(byte[] bytes) {
+        if (bytes.length != UUID_BYTE_SIZE) {
+            throw new IllegalArgumentException("Expected array of size " + UUID_BYTE_SIZE
+                                               + ", got " + bytes.length);
+        }
+        final ByteBuffer buf = ByteBuffer.wrap(bytes);
+        long msb = buf.getLong();
+        long lsb = buf.getLong();
+        return new UUID(msb, lsb);
+    }
+
+    /**
+     * Returns the metadata object of an IncFs File.
+     *
+     * @param id The file id.
+     * @return Byte array that contains metadata bytes.
+     */
+    @Nullable
+    public byte[] getFileMetadata(@NonNull UUID id) {
+        try {
+            final byte[] rawId = idToBytes(id);
+            return mService.getMetadataById(mId, rawId);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
             return null;
diff --git a/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp b/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp
index 4e49302..01150b7 100644
--- a/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp
+++ b/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp
@@ -32,6 +32,7 @@
 #include <utils/Log.h>
 
 #include <charconv>
+#include <span>
 #include <string>
 #include <thread>
 #include <type_traits>
@@ -92,9 +93,7 @@
 
 static_assert(COMMAND_SIZE == sizeof(RequestCommand));
 
-static bool sendRequest(int fd,
-                        RequestType requestType,
-                        FileId fileId = -1,
+static bool sendRequest(int fd, RequestType requestType, FileId fileId = -1,
                         BlockIdx blockIdx = -1) {
     const RequestCommand command{
             .requestType = static_cast<int16_t>(be16toh(requestType)),
@@ -267,25 +266,24 @@
         std::lock_guard lock{mMapsMutex};
         CHECK(mIfs);
         for (auto&& pendingRead : pendingReads) {
-            const android::dataloader::Inode ino = pendingRead.file_ino;
-            const auto blockIdx =
-                    static_cast<BlockIdx>(pendingRead.block_index);
+            const android::dataloader::FileId id = pendingRead.id;
+            const auto blockIdx = static_cast<BlockIdx>(pendingRead.block);
             /*
             ALOGI("[AdbDataLoader] Missing: %d", (int) blockIdx);
             */
-            auto fileIdOr = getFileId(ino);
+            auto fileIdOr = getFileId(id);
             if (!fileIdOr) {
-                ALOGE("[AdbDataLoader] Failed to handle event for inode=%d. "
+                ALOGE("[AdbDataLoader] Failed to handle event for fileid=%s. "
                       "Ignore.",
-                      static_cast<int>(ino));
+                      android::incfs::toString(id).c_str());
                 continue;
             }
             const FileId fileId = *fileIdOr;
             if (mRequestedFiles.insert(fileId).second) {
                 if (!sendRequest(mOutFd, PREFETCH, fileId, blockIdx)) {
                     ALOGE("[AdbDataLoader] Failed to request prefetch for "
-                          "inode=%d. Ignore.",
-                          static_cast<int>(ino));
+                          "fileid=%s. Ignore.",
+                          android::incfs::toString(id).c_str());
                     mRequestedFiles.erase(fileId);
                     mStatusListener->reportStatus(DATA_LOADER_NO_CONNECTION);
                 }
@@ -296,7 +294,7 @@
 
     struct TracedRead {
         uint64_t timestampUs;
-        uint64_t fileIno;
+        android::dataloader::FileId fileId;
         uint32_t firstBlockIdx;
         uint32_t count;
     };
@@ -307,26 +305,26 @@
             return;
         }
 
-        TracedRead last = {0, 0, 0, 0};
+        TracedRead last = {};
         std::lock_guard lock{mMapsMutex};
         for (auto&& read : pageReads) {
-            if (read.file_ino != last.fileIno ||
-                read.block_index != last.firstBlockIdx + last.count) {
+            if (read.id != last.fileId || read.block != last.firstBlockIdx + last.count) {
                 traceOrLogRead(last, trace, log);
-                last = {read.timestamp_us, read.file_ino, read.block_index, 1};
+                last = {read.bootClockTsUs, read.id, (uint32_t)read.block, 1};
             } else {
                 ++last.count;
             }
         }
         traceOrLogRead(last, trace, log);
     }
-    void onFileCreated(android::dataloader::Inode inode, const android::dataloader::RawMetadata& metadata) {
-    }
+    void onFileCreated(android::dataloader::FileId fileid,
+                       const android::dataloader::RawMetadata& metadata) {}
 
 private:
     void receiver() {
         std::vector<uint8_t> data;
-        std::vector<incfs_new_data_block> instructions;
+        std::vector<IncFsDataBlock> instructions;
+        std::unordered_map<android::dataloader::FileId, unique_fd> writeFds;
         while (!mStopReceiving) {
             const int res = waitForDataOrSignal(mInFd, mEventFd);
             if (res == 0) {
@@ -366,21 +364,32 @@
                     mStopReceiving = true;
                     break;
                 }
-                const android::dataloader::Inode ino = mIdToNodeMap[header.fileId];
-                if (!ino) {
+                const android::dataloader::FileId id = mIdToNodeMap[header.fileId];
+                if (!android::incfs::isValidFileId(id)) {
                     ALOGE("Unknown data destination for file ID %d. "
                           "Ignore.",
                           header.fileId);
                     continue;
                 }
-                auto inst = incfs_new_data_block{
-                        .file_ino = static_cast<__aligned_u64>(ino),
-                        .block_index = static_cast<uint32_t>(header.blockIdx),
-                        .data_len = static_cast<uint16_t>(header.blockSize),
-                        .data = reinterpret_cast<uint64_t>(
-                                remainingData.data()),
-                        .compression =
-                                static_cast<uint8_t>(header.compressionType)};
+
+                auto& writeFd = writeFds[id];
+                if (writeFd < 0) {
+                    writeFd.reset(this->mIfs->openWrite(id));
+                    if (writeFd < 0) {
+                        ALOGE("Failed to open file %d for writing (%d). Aboring.", header.fileId,
+                              -writeFd);
+                        break;
+                    }
+                }
+
+                const auto inst = IncFsDataBlock{
+                        .fileFd = writeFd,
+                        .pageIndex = static_cast<IncFsBlockIndex>(header.blockIdx),
+                        .compression = static_cast<IncFsCompressionKind>(header.compressionType),
+                        .kind = INCFS_BLOCK_KIND_DATA,
+                        .dataSize = static_cast<uint16_t>(header.blockSize),
+                        .data = (const char*)remainingData.data(),
+                };
                 instructions.push_back(inst);
                 remainingData = remainingData.subspan(header.blockSize);
             }
@@ -390,9 +399,8 @@
         flushReadLog();
     }
 
-    void writeInstructions(std::vector<incfs_new_data_block>& instructions) {
-        auto res = this->mIfs->writeBlocks(instructions.data(),
-                                           instructions.size());
+    void writeInstructions(std::vector<IncFsDataBlock>& instructions) {
+        auto res = this->mIfs->writeBlocks(instructions);
         if (res != instructions.size()) {
             ALOGE("[AdbDataLoader] failed to write data to Incfs (res=%d when "
                   "expecting %d)",
@@ -406,30 +414,30 @@
         FileId fileId;
     };
 
-    MetaPair* updateMapsForFile(android::dataloader::Inode ino) {
-        android::dataloader::RawMetadata meta = mIfs->getRawMetadata(ino);
+    MetaPair* updateMapsForFile(android::dataloader::FileId id) {
+        android::dataloader::RawMetadata meta = mIfs->getRawMetadata(id);
         FileId fileId;
         auto res =
                 std::from_chars(meta.data(), meta.data() + meta.size(), fileId);
         if (res.ec != std::errc{} || fileId < 0) {
-            ALOGE("[AdbDataLoader] Invalid metadata for inode=%d (%s)",
-                  static_cast<int>(ino), meta.data());
+            ALOGE("[AdbDataLoader] Invalid metadata for fileid=%s (%s)",
+                  android::incfs::toString(id).c_str(), meta.data());
             return nullptr;
         }
-        mIdToNodeMap[fileId] = ino;
-        auto& metaPair = mNodeToMetaMap[ino];
+        mIdToNodeMap[fileId] = id;
+        auto& metaPair = mNodeToMetaMap[id];
         metaPair.meta = std::move(meta);
         metaPair.fileId = fileId;
         return &metaPair;
     }
 
-    android::dataloader::RawMetadata* getMeta(android::dataloader::Inode ino) {
-        auto it = mNodeToMetaMap.find(ino);
+    android::dataloader::RawMetadata* getMeta(android::dataloader::FileId id) {
+        auto it = mNodeToMetaMap.find(id);
         if (it != mNodeToMetaMap.end()) {
             return &it->second.meta;
         }
 
-        auto metaPair = updateMapsForFile(ino);
+        auto metaPair = updateMapsForFile(id);
         if (!metaPair) {
             return nullptr;
         }
@@ -437,13 +445,13 @@
         return &metaPair->meta;
     }
 
-    FileId* getFileId(android::dataloader::Inode ino) {
-        auto it = mNodeToMetaMap.find(ino);
+    FileId* getFileId(android::dataloader::FileId id) {
+        auto it = mNodeToMetaMap.find(id);
         if (it != mNodeToMetaMap.end()) {
             return &it->second.fileId;
         }
 
-        auto* metaPair = updateMapsForFile(ino);
+        auto* metaPair = updateMapsForFile(id);
         if (!metaPair) {
             return nullptr;
         }
@@ -456,7 +464,7 @@
             return;
         }
         if (trace) {
-            auto* meta = getMeta(read.fileIno);
+            auto* meta = getMeta(read.fileId);
             auto str = android::base::StringPrintf(
                     "page_read: index=%lld count=%lld meta=%.*s",
                     static_cast<long long>(read.firstBlockIdx),
@@ -468,7 +476,7 @@
         if (log) {
             mReadLog.reserve(ReadLogBufferSize);
 
-            auto fileId = getFileId(read.fileIno);
+            auto fileId = getFileId(read.fileId);
             android::base::StringAppendF(
                     &mReadLog, "%lld:%lld:%lld:%lld\n",
                     static_cast<long long>(read.timestampUs),
@@ -501,8 +509,8 @@
     std::string mReadLog;
     std::thread mReceiverThread;
     std::mutex mMapsMutex;
-    std::unordered_map<android::dataloader::Inode, MetaPair> mNodeToMetaMap GUARDED_BY(mMapsMutex);
-    std::unordered_map<FileId, android::dataloader::Inode> mIdToNodeMap GUARDED_BY(mMapsMutex);
+    std::unordered_map<android::dataloader::FileId, MetaPair> mNodeToMetaMap GUARDED_BY(mMapsMutex);
+    std::unordered_map<FileId, android::dataloader::FileId> mIdToNodeMap GUARDED_BY(mMapsMutex);
     /** Tracks which files have been requested */
     std::unordered_set<FileId> mRequestedFiles;
     std::atomic<bool> mStopReceiving = false;
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerService.java b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
index d673ec8..5876d43 100644
--- a/services/core/java/com/android/server/incremental/IncrementalManagerService.java
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
@@ -134,7 +134,7 @@
 
     // TODO: remove this
     @Override
-    public void newFileForDataLoader(int mountId, long inode, byte[] metadata) {
+    public void newFileForDataLoader(int mountId, byte[] fileId, byte[] metadata) {
         IDataLoader dataLoader = mDataLoaderManager.getDataLoader(mountId);
         if (dataLoader == null) {
             Slog.e(TAG, "Failed to retrieve data loader for ID=" + mountId);
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp
index ddf4dd5..323e7f1 100644
--- a/services/incremental/Android.bp
+++ b/services/incremental/Android.bp
@@ -47,6 +47,8 @@
     shared_libs: [
         "libandroidfw",
         "libbinder",
+        "libcrypto",
+        "libcutils",
         "libincfs",
         "liblog",
         "libz",
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index bb26c1f..f1b637f 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -46,10 +46,10 @@
     return incfs::enabled();
 }
 
-static bool incFsVersionValid(const sp<IVold>& vold) {
-    int version = -1;
-    auto status = vold->incFsVersion(&version);
-    if (!status.isOk() || version <= 0) {
+static bool incFsValid(const sp<IVold>& vold) {
+    bool enabled = false;
+    auto status = vold->incFsEnabled(&enabled);
+    if (!status.isOk() || !enabled) {
         return false;
     }
     return true;
@@ -74,7 +74,7 @@
         return nullptr;
     }
     sp<IVold> vold = interface_cast<IVold>(voldBinder);
-    if (!incFsVersionValid(vold)) {
+    if (!incFsValid(vold)) {
         return nullptr;
     }
 
@@ -86,6 +86,7 @@
     sp<ProcessState> ps(ProcessState::self());
     ps->startThreadPool();
     ps->giveThreadPoolName();
+    // sm->addService increments the reference count, and now we're OK with returning the pointer.
     return self.get();
 }
 
@@ -107,9 +108,9 @@
     return ok();
 }
 
-binder::Status BinderIncrementalService::createStorage(
-        const std::string& path, const DataLoaderParamsParcel& params,
-        int32_t createMode, int32_t* _aidl_return) {
+binder::Status BinderIncrementalService::createStorage(const std::string& path,
+                                                       const DataLoaderParamsParcel& params,
+                                                       int32_t createMode, int32_t* _aidl_return) {
     *_aidl_return =
             mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params),
                                 android::incremental::IncrementalService::CreateOptions(
@@ -129,10 +130,10 @@
 }
 
 binder::Status BinderIncrementalService::makeBindMount(int32_t storageId,
-                                                       const std::string& pathUnderStorage,
+                                                       const std::string& sourcePath,
                                                        const std::string& targetFullPath,
                                                        int32_t bindType, int32_t* _aidl_return) {
-    *_aidl_return = mImpl.bind(storageId, pathUnderStorage, targetFullPath,
+    *_aidl_return = mImpl.bind(storageId, sourcePath, targetFullPath,
                                android::incremental::IncrementalService::BindKind(bindType));
     return ok();
 }
@@ -149,75 +150,127 @@
     return ok();
 }
 
-binder::Status BinderIncrementalService::makeDirectory(int32_t storageId,
-                                                       const std::string& pathUnderStorage,
+binder::Status BinderIncrementalService::makeDirectory(int32_t storageId, const std::string& path,
                                                        int32_t* _aidl_return) {
-    auto inode = mImpl.makeDir(storageId, pathUnderStorage);
-    *_aidl_return = inode < 0 ? inode : 0;
+    *_aidl_return = mImpl.makeDir(storageId, path);
     return ok();
 }
 
-binder::Status BinderIncrementalService::makeDirectories(int32_t storageId,
-                                                         const std::string& pathUnderStorage,
-                                                         int32_t* _aidl_return) {
-    auto inode = mImpl.makeDirs(storageId, pathUnderStorage);
-    *_aidl_return = inode < 0 ? inode : 0;
-    return ok();
+static std::tuple<int, incfs::FileId, incfs::NewFileParams> toMakeFileParams(
+        const android::os::incremental::IncrementalNewFileParams& params) {
+    incfs::FileId id;
+    if (params.fileId.empty()) {
+        if (params.metadata.empty()) {
+            return {EINVAL, {}, {}};
+        }
+        id = IncrementalService::idFromMetadata(params.metadata);
+    } else if (params.fileId.size() != sizeof(id)) {
+        return {EINVAL, {}, {}};
+    } else {
+        memcpy(&id, params.fileId.data(), sizeof(id));
+    }
+    incfs::NewFileParams nfp;
+    nfp.size = params.size;
+    nfp.metadata = {(const char*)params.metadata.data(), (IncFsSize)params.metadata.size()};
+    if (!params.signature) {
+        nfp.verification = {};
+    } else {
+        nfp.verification.hashAlgorithm = IncFsHashAlgortithm(params.signature->hashAlgorithm);
+        nfp.verification.rootHash = {(const char*)params.signature->rootHash.data(),
+                                     (IncFsSize)params.signature->rootHash.size()};
+        nfp.verification.additionalData = {(const char*)params.signature->additionalData.data(),
+                                           (IncFsSize)params.signature->additionalData.size()};
+        nfp.verification.signature = {(const char*)params.signature->signature.data(),
+                                      (IncFsSize)params.signature->signature.size()};
+    }
+    return {0, id, nfp};
 }
 
-binder::Status BinderIncrementalService::makeFile(int32_t storageId,
-                                                  const std::string& pathUnderStorage, int64_t size,
-                                                  const std::vector<uint8_t>& metadata,
-                                                  int32_t* _aidl_return) {
-    auto inode = mImpl.makeFile(storageId, pathUnderStorage, size,
-                                {(const char*)metadata.data(), metadata.size()}, {});
-    *_aidl_return = inode < 0 ? inode : 0;
+binder::Status BinderIncrementalService::makeFile(
+        int32_t storageId, const std::string& path,
+        const ::android::os::incremental::IncrementalNewFileParams& params, int32_t* _aidl_return) {
+    auto [err, fileId, nfp] = toMakeFileParams(params);
+    if (err) {
+        *_aidl_return = err;
+        return ok();
+    }
+
+    *_aidl_return = mImpl.makeFile(storageId, path, 0555, fileId, nfp);
     return ok();
 }
-binder::Status BinderIncrementalService::makeFileFromRange(
-        int32_t storageId, const std::string& pathUnderStorage,
-        const std::string& sourcePathUnderStorage, int64_t start, int64_t end,
-        int32_t* _aidl_return) {
-    // TODO(b/136132412): implement this
-    *_aidl_return = -1;
-    return ok();
-}
-binder::Status BinderIncrementalService::makeLink(int32_t sourceStorageId,
-                                                  const std::string& relativeSourcePath,
-                                                  int32_t destStorageId,
-                                                  const std::string& relativeDestPath,
-                                                  int32_t* _aidl_return) {
-    auto sourceInode = mImpl.nodeFor(sourceStorageId, relativeSourcePath);
-    auto [targetParentInode, name] = mImpl.parentAndNameFor(destStorageId, relativeDestPath);
-    *_aidl_return = mImpl.link(sourceStorageId, sourceInode, targetParentInode, name);
-    return ok();
-}
-binder::Status BinderIncrementalService::unlink(int32_t storageId,
-                                                const std::string& pathUnderStorage,
-                                                int32_t* _aidl_return) {
-    auto [parentNode, name] = mImpl.parentAndNameFor(storageId, pathUnderStorage);
-    *_aidl_return = mImpl.unlink(storageId, parentNode, name);
-    return ok();
-}
-binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId,
-                                                           const std::string& relativePath,
+binder::Status BinderIncrementalService::makeFileFromRange(int32_t storageId,
+                                                           const std::string& targetPath,
+                                                           const std::string& sourcePath,
                                                            int64_t start, int64_t end,
-                                                           bool* _aidl_return) {
+                                                           int32_t* _aidl_return) {
+    // TODO(b/136132412): implement this
+    *_aidl_return = ENOSYS; // not implemented
+    return ok();
+}
+
+binder::Status BinderIncrementalService::makeLink(int32_t sourceStorageId,
+                                                  const std::string& sourcePath,
+                                                  int32_t destStorageId,
+                                                  const std::string& destPath,
+                                                  int32_t* _aidl_return) {
+    *_aidl_return = mImpl.link(sourceStorageId, sourcePath, destStorageId, destPath);
+    return ok();
+}
+
+binder::Status BinderIncrementalService::unlink(int32_t storageId, const std::string& path,
+                                                int32_t* _aidl_return) {
+    *_aidl_return = mImpl.unlink(storageId, path);
+    return ok();
+}
+
+binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId,
+                                                           const std::string& path, int64_t start,
+                                                           int64_t end, bool* _aidl_return) {
+    // TODO: implement
     *_aidl_return = false;
     return ok();
 }
-binder::Status BinderIncrementalService::getFileMetadata(int32_t storageId,
-                                                         const std::string& relativePath,
+
+binder::Status BinderIncrementalService::getMetadataByPath(int32_t storageId,
+                                                           const std::string& path,
+                                                           std::vector<uint8_t>* _aidl_return) {
+    auto fid = mImpl.nodeFor(storageId, path);
+    if (fid != kIncFsInvalidFileId) {
+        auto metadata = mImpl.getMetadata(storageId, fid);
+        _aidl_return->assign(metadata.begin(), metadata.end());
+    }
+    return ok();
+}
+
+static FileId toFileId(const std::vector<uint8_t>& id) {
+    FileId fid;
+    memcpy(&fid, id.data(), id.size());
+    return fid;
+}
+
+binder::Status BinderIncrementalService::getMetadataById(int32_t storageId,
+                                                         const std::vector<uint8_t>& id,
                                                          std::vector<uint8_t>* _aidl_return) {
-    auto inode = mImpl.nodeFor(storageId, relativePath);
-    auto metadata = mImpl.getMetadata(storageId, inode);
+    if (id.size() != sizeof(incfs::FileId)) {
+        return ok();
+    }
+    auto fid = toFileId(id);
+    auto metadata = mImpl.getMetadata(storageId, fid);
     _aidl_return->assign(metadata.begin(), metadata.end());
     return ok();
 }
+
+binder::Status BinderIncrementalService::makeDirectories(int32_t storageId, const std::string& path,
+                                                         int32_t* _aidl_return) {
+    *_aidl_return = mImpl.makeDirs(storageId, path);
+    return ok();
+}
+
 binder::Status BinderIncrementalService::startLoading(int32_t storageId, bool* _aidl_return) {
     *_aidl_return = mImpl.startLoading(storageId);
     return ok();
 }
+
 } // namespace android::os::incremental
 
 jlong Incremental_IncrementalService_Start() {
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 37c9661d..a94a75a 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -37,38 +37,39 @@
     void onSystemReady();
     void onInvalidStorage(int mountId);
 
-    binder::Status openStorage(const std::string &path, int32_t *_aidl_return) final;
-    binder::Status createStorage(
-            const std::string &path,
-            const ::android::content::pm::DataLoaderParamsParcel &params,
-            int32_t createMode, int32_t *_aidl_return) final;
-    binder::Status createLinkedStorage(const std::string &path, int32_t otherStorageId,
-                                       int32_t createMode, int32_t *_aidl_return) final;
-    binder::Status makeBindMount(int32_t storageId, const std::string &pathUnderStorage,
-                                 const std::string &targetFullPath, int32_t bindType,
-                                 int32_t *_aidl_return) final;
-    binder::Status deleteBindMount(int32_t storageId, const std::string &targetFullPath,
-                                   int32_t *_aidl_return) final;
+    binder::Status openStorage(const std::string& path, int32_t* _aidl_return) final;
+    binder::Status createStorage(const std::string& path,
+                                 const ::android::content::pm::DataLoaderParamsParcel& params,
+                                 int32_t createMode, int32_t* _aidl_return) final;
+    binder::Status createLinkedStorage(const std::string& path, int32_t otherStorageId,
+                                       int32_t createMode, int32_t* _aidl_return) final;
+    binder::Status makeBindMount(int32_t storageId, const std::string& sourcePath,
+                                 const std::string& targetFullPath, int32_t bindType,
+                                 int32_t* _aidl_return) final;
+    binder::Status deleteBindMount(int32_t storageId, const std::string& targetFullPath,
+                                   int32_t* _aidl_return) final;
+    binder::Status makeDirectory(int32_t storageId, const std::string& path,
+                                 int32_t* _aidl_return) final;
+    binder::Status makeDirectories(int32_t storageId, const std::string& path,
+                                   int32_t* _aidl_return) final;
+    binder::Status makeFile(int32_t storageId, const std::string& path,
+                            const ::android::os::incremental::IncrementalNewFileParams& params,
+                            int32_t* _aidl_return) final;
+    binder::Status makeFileFromRange(int32_t storageId, const std::string& targetPath,
+                                     const std::string& sourcePath, int64_t start, int64_t end,
+                                     int32_t* _aidl_return) final;
+    binder::Status makeLink(int32_t sourceStorageId, const std::string& sourcePath,
+                            int32_t destStorageId, const std::string& destPath,
+                            int32_t* _aidl_return) final;
+    binder::Status unlink(int32_t storageId, const std::string& path, int32_t* _aidl_return) final;
+    binder::Status isFileRangeLoaded(int32_t storageId, const std::string& path, int64_t start,
+                                     int64_t end, bool* _aidl_return) final;
+    binder::Status getMetadataByPath(int32_t storageId, const std::string& path,
+                                     std::vector<uint8_t>* _aidl_return) final;
+    binder::Status getMetadataById(int32_t storageId, const std::vector<uint8_t>& id,
+                                   std::vector<uint8_t>* _aidl_return) final;
+    binder::Status startLoading(int32_t storageId, bool* _aidl_return) final;
     binder::Status deleteStorage(int32_t storageId) final;
-    binder::Status makeDirectory(int32_t storageId, const std::string &pathUnderStorage,
-                                 int32_t *_aidl_return) final;
-    binder::Status makeDirectories(int32_t storageId, const std::string &pathUnderStorage,
-                                   int32_t *_aidl_return) final;
-    binder::Status makeFile(int32_t storageId, const std::string &pathUnderStorage, int64_t size,
-                            const std::vector<uint8_t> &metadata, int32_t *_aidl_return) final;
-    binder::Status makeFileFromRange(int32_t storageId, const std::string &pathUnderStorage,
-                                     const std::string &sourcePathUnderStorage, int64_t start,
-                                     int64_t end, int32_t *_aidl_return);
-    binder::Status makeLink(int32_t sourceStorageId, const std::string &relativeSourcePath,
-                            int32_t destStorageId, const std::string &relativeDestPath,
-                            int32_t *_aidl_return) final;
-    binder::Status unlink(int32_t storageId, const std::string &pathUnderStorage,
-                          int32_t *_aidl_return) final;
-    binder::Status isFileRangeLoaded(int32_t storageId, const std::string &relativePath,
-                                     int64_t start, int64_t end, bool *_aidl_return) final;
-    binder::Status getFileMetadata(int32_t storageId, const std::string &relativePath,
-                                   std::vector<uint8_t> *_aidl_return) final;
-    binder::Status startLoading(int32_t storageId, bool *_aidl_return) final;
 
 private:
     android::incremental::IncrementalService mImpl;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index afce260..414c66c 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -30,6 +30,8 @@
 #include <binder/BinderService.h>
 #include <binder/ParcelFileDescriptor.h>
 #include <binder/Status.h>
+
+#include <openssl/sha.h>
 #include <sys/stat.h>
 #include <uuid/uuid.h>
 #include <zlib.h>
@@ -55,7 +57,6 @@
 struct Constants {
     static constexpr auto backing = "backing_store"sv;
     static constexpr auto mount = "mount"sv;
-    static constexpr auto image = "incfs.img"sv;
     static constexpr auto storagePrefix = "st"sv;
     static constexpr auto mountpointMdPrefix = ".mountpoint."sv;
     static constexpr auto infoMdName = ".info"sv;
@@ -70,7 +71,7 @@
 bool mkdirOrLog(std::string_view name, int mode = 0770, bool allowExisting = true) {
     auto cstr = path::c_str(name);
     if (::mkdir(cstr, mode)) {
-        if (errno != EEXIST) {
+        if (!allowExisting || errno != EEXIST) {
             PLOG(level) << "Can't create directory '" << name << '\'';
             return false;
         }
@@ -80,6 +81,11 @@
             return false;
         }
     }
+    if (::chmod(cstr, mode)) {
+        PLOG(level) << "Changing permission failed for '" << name << '\'';
+        return false;
+    }
+
     return true;
 }
 
@@ -106,7 +112,7 @@
     for (int counter = 0; counter < 1000;
          mountKey.resize(prefixSize), base::StringAppendF(&mountKey, "%d", counter++)) {
         auto mountRoot = path::join(incrementalDir, mountKey);
-        if (mkdirOrLog(mountRoot, 0770, false)) {
+        if (mkdirOrLog(mountRoot, 0777, false)) {
             return {mountKey, mountRoot};
         }
     }
@@ -116,11 +122,7 @@
 template <class ProtoMessage, class Control>
 static ProtoMessage parseFromIncfs(const IncFsWrapper* incfs, Control&& control,
                                    std::string_view path) {
-    struct stat st;
-    if (::stat(path::c_str(path), &st)) {
-        return {};
-    }
-    auto md = incfs->getMetadata(control, st.st_ino);
+    auto md = incfs->getMetadata(control, path);
     ProtoMessage message;
     return message.ParseFromArray(md.data(), md.size()) ? message : ProtoMessage{};
 }
@@ -161,35 +163,66 @@
 }
 
 auto IncrementalService::IncFsMount::makeStorage(StorageId id) -> StorageMap::iterator {
-    metadata::Storage st;
-    st.set_id(id);
-    auto metadata = st.SerializeAsString();
-
     std::string name;
     for (int no = nextStorageDirNo.fetch_add(1, std::memory_order_relaxed), i = 0;
          i < 1024 && no >= 0; no = nextStorageDirNo.fetch_add(1, std::memory_order_relaxed), ++i) {
         name.clear();
-        base::StringAppendF(&name, "%.*s%d", int(constants().storagePrefix.size()),
-                            constants().storagePrefix.data(), no);
-        if (auto node =
-                    incrementalService.mIncFs->makeDir(control, name, INCFS_ROOT_INODE, metadata);
-            node >= 0) {
+        base::StringAppendF(&name, "%.*s_%d_%d", int(constants().storagePrefix.size()),
+                            constants().storagePrefix.data(), id, no);
+        auto fullName = path::join(root, constants().mount, name);
+        if (auto err = incrementalService.mIncFs->makeDir(control, fullName); !err) {
             std::lock_guard l(lock);
-            return storages.insert_or_assign(id, Storage{std::move(name), node}).first;
+            return storages.insert_or_assign(id, Storage{std::move(fullName)}).first;
+        } else if (err != EEXIST) {
+            LOG(ERROR) << __func__ << "(): failed to create dir |" << fullName << "| " << err;
+            break;
         }
     }
     nextStorageDirNo = 0;
     return storages.end();
 }
 
+static std::unique_ptr<DIR, decltype(&::closedir)> openDir(const char* path) {
+    return {::opendir(path), ::closedir};
+}
+
+static int rmDirContent(const char* path) {
+    auto dir = openDir(path);
+    if (!dir) {
+        return -EINVAL;
+    }
+    while (auto entry = ::readdir(dir.get())) {
+        if (entry->d_name == "."sv || entry->d_name == ".."sv) {
+            continue;
+        }
+        auto fullPath = android::base::StringPrintf("%s/%s", path, entry->d_name);
+        if (entry->d_type == DT_DIR) {
+            if (const auto err = rmDirContent(fullPath.c_str()); err != 0) {
+                PLOG(WARNING) << "Failed to delete " << fullPath << " content";
+                return err;
+            }
+            if (const auto err = ::rmdir(fullPath.c_str()); err != 0) {
+                PLOG(WARNING) << "Failed to rmdir " << fullPath;
+                return err;
+            }
+        } else {
+            if (const auto err = ::unlink(fullPath.c_str()); err != 0) {
+                PLOG(WARNING) << "Failed to delete " << fullPath;
+                return err;
+            }
+        }
+    }
+    return 0;
+}
+
 void IncrementalService::IncFsMount::cleanupFilesystem(std::string_view root) {
-    ::unlink(path::join(root, constants().backing, constants().image).c_str());
+    rmDirContent(path::join(root, constants().backing).c_str());
     ::rmdir(path::join(root, constants().backing).c_str());
     ::rmdir(path::join(root, constants().mount).c_str());
     ::rmdir(path::c_str(root));
 }
 
-IncrementalService::IncrementalService(const ServiceManagerWrapper& sm, std::string_view rootDir)
+IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir)
       : mVold(sm.getVoldService()),
         mIncrementalManager(sm.getIncrementalManager()),
         mIncFs(sm.getIncFs()),
@@ -205,6 +238,23 @@
     // mountExistingImages();
 }
 
+FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) {
+    incfs::FileId id = {};
+    if (size_t(metadata.size()) <= sizeof(id)) {
+        memcpy(&id, metadata.data(), metadata.size());
+    } else {
+        uint8_t buffer[SHA_DIGEST_LENGTH];
+        static_assert(sizeof(buffer) >= sizeof(id));
+
+        SHA_CTX ctx;
+        SHA1_Init(&ctx);
+        SHA1_Update(&ctx, metadata.data(), metadata.size());
+        SHA1_Final(buffer, &ctx);
+        memcpy(&id, buffer, sizeof(id));
+    }
+    return id;
+}
+
 IncrementalService::~IncrementalService() = default;
 
 std::optional<std::future<void>> IncrementalService::onSystemReady() {
@@ -300,26 +350,36 @@
             std::unique_ptr<std::string, decltype(firstCleanup)>(&mountRoot, firstCleanup);
 
     auto mountTarget = path::join(mountRoot, constants().mount);
-    if (!mkdirOrLog(path::join(mountRoot, constants().backing)) || !mkdirOrLog(mountTarget)) {
+    const auto backing = path::join(mountRoot, constants().backing);
+    if (!mkdirOrLog(backing, 0777) || !mkdirOrLog(mountTarget)) {
         return kInvalidStorageId;
     }
 
-    const auto image = path::join(mountRoot, constants().backing, constants().image);
     IncFsMount::Control control;
     {
         std::lock_guard l(mMountOperationLock);
         IncrementalFileSystemControlParcel controlParcel;
-        auto status = mVold->mountIncFs(image, mountTarget, incfs::truncate, &controlParcel);
+
+        if (auto err = rmDirContent(backing.c_str())) {
+            LOG(ERROR) << "Coudn't clean the backing directory " << backing << ": " << err;
+            return kInvalidStorageId;
+        }
+        if (!mkdirOrLog(path::join(backing, ".index"), 0777)) {
+            return kInvalidStorageId;
+        }
+        auto status = mVold->mountIncFs(backing, mountTarget, 0, &controlParcel);
         if (!status.isOk()) {
             LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();
             return kInvalidStorageId;
         }
-        if (!controlParcel.cmd || !controlParcel.log) {
+        if (controlParcel.cmd.get() < 0 || controlParcel.pendingReads.get() < 0 ||
+            controlParcel.log.get() < 0) {
             LOG(ERROR) << "Vold::mountIncFs() returned invalid control parcel.";
             return kInvalidStorageId;
         }
-        control.cmdFd = controlParcel.cmd->release();
-        control.logFd = controlParcel.log->release();
+        control.cmd = controlParcel.cmd.release().release();
+        control.pendingReads = controlParcel.pendingReads.release().release();
+        control.logs = controlParcel.log.release().release();
     }
 
     std::unique_lock l(mLock);
@@ -344,7 +404,7 @@
 
     const auto storageIt = ifs->makeStorage(ifs->mountId);
     if (storageIt == ifs->storages.end()) {
-        LOG(ERROR) << "Can't create default storage directory";
+        LOG(ERROR) << "Can't create a default storage directory";
         return kInvalidStorageId;
     }
 
@@ -359,9 +419,12 @@
         m.mutable_loader()->release_arguments();
         m.mutable_loader()->release_class_name();
         m.mutable_loader()->release_package_name();
-        if (auto err = mIncFs->makeFile(ifs->control, constants().infoMdName, INCFS_ROOT_INODE, 0,
-                                        metadata);
-            err < 0) {
+        if (auto err =
+                    mIncFs->makeFile(ifs->control,
+                                     path::join(ifs->root, constants().mount,
+                                                constants().infoMdName),
+                                     0777, idFromMetadata(metadata),
+                                     {.metadata = {metadata.data(), (IncFsSize)metadata.size()}})) {
             LOG(ERROR) << "Saving mount metadata failed: " << -err;
             return kInvalidStorageId;
         }
@@ -369,8 +432,8 @@
 
     const auto bk =
             (options & CreateOptions::PermanentBind) ? BindKind::Permanent : BindKind::Temporary;
-    if (auto err = addBindMount(*ifs, storageIt->first, std::string(storageIt->second.name),
-                                std::move(mountNorm), bk, l);
+    if (auto err = addBindMount(*ifs, storageIt->first, storageIt->second.name,
+                                std::string(storageIt->second.name), std::move(mountNorm), bk, l);
         err < 0) {
         LOG(ERROR) << "adding bind mount failed: " << -err;
         return kInvalidStorageId;
@@ -419,8 +482,9 @@
 
     const auto bk =
             (options & CreateOptions::PermanentBind) ? BindKind::Permanent : BindKind::Temporary;
-    if (auto err = addBindMount(*ifs, storageIt->first, std::string(storageIt->second.name),
-                                path::normalize(mountPoint), bk, l);
+    if (auto err = addBindMount(*ifs, storageIt->first, storageIt->second.name,
+                                std::string(storageIt->second.name), path::normalize(mountPoint),
+                                bk, l);
         err < 0) {
         LOG(ERROR) << "bindMount failed with error: " << err;
         return kInvalidStorageId;
@@ -492,40 +556,36 @@
     return findStorageId(path::normalize(pathInMount));
 }
 
-Inode IncrementalService::nodeFor(StorageId storage, std::string_view subpath) const {
+FileId IncrementalService::nodeFor(StorageId storage, std::string_view subpath) const {
     const auto ifs = getIfs(storage);
     if (!ifs) {
-        return -1;
+        return kIncFsInvalidFileId;
     }
     std::unique_lock l(ifs->lock);
     auto storageIt = ifs->storages.find(storage);
     if (storageIt == ifs->storages.end()) {
-        return -1;
+        return kIncFsInvalidFileId;
     }
     if (subpath.empty() || subpath == "."sv) {
-        return storageIt->second.node;
+        return kIncFsInvalidFileId;
     }
     auto path = path::join(ifs->root, constants().mount, storageIt->second.name, subpath);
     l.unlock();
-    struct stat st;
-    if (::stat(path.c_str(), &st)) {
-        return -1;
-    }
-    return st.st_ino;
+    return mIncFs->getFileId(ifs->control, path);
 }
 
-std::pair<Inode, std::string_view> IncrementalService::parentAndNameFor(
+std::pair<FileId, std::string_view> IncrementalService::parentAndNameFor(
         StorageId storage, std::string_view subpath) const {
     auto name = path::basename(subpath);
     if (name.empty()) {
-        return {-1, {}};
+        return {kIncFsInvalidFileId, {}};
     }
     auto dir = path::dirname(subpath);
     if (dir.empty() || dir == "/"sv) {
-        return {-1, {}};
+        return {kIncFsInvalidFileId, {}};
     }
-    auto inode = nodeFor(storage, dir);
-    return {inode, name};
+    auto id = nodeFor(storage, dir);
+    return {id, name};
 }
 
 IncrementalService::IfsMountPtr IncrementalService::getIfs(StorageId storage) const {
@@ -542,8 +602,8 @@
     return it->second;
 }
 
-int IncrementalService::bind(StorageId storage, std::string_view sourceSubdir,
-                             std::string_view target, BindKind kind) {
+int IncrementalService::bind(StorageId storage, std::string_view source, std::string_view target,
+                             BindKind kind) {
     if (!isValidMountTarget(target)) {
         return -EINVAL;
     }
@@ -552,15 +612,20 @@
     if (!ifs) {
         return -EINVAL;
     }
+    auto normSource = path::normalize(source);
+
     std::unique_lock l(ifs->lock);
     const auto storageInfo = ifs->storages.find(storage);
     if (storageInfo == ifs->storages.end()) {
         return -EINVAL;
     }
-    auto source = path::join(storageInfo->second.name, sourceSubdir);
+    if (!path::startsWith(normSource, storageInfo->second.name)) {
+        return -EINVAL;
+    }
     l.unlock();
     std::unique_lock l2(mLock, std::defer_lock);
-    return addBindMount(*ifs, storage, std::move(source), path::normalize(target), kind, l2);
+    return addBindMount(*ifs, storage, storageInfo->second.name, std::move(normSource),
+                        path::normalize(target), kind, l2);
 }
 
 int IncrementalService::unbind(StorageId storage, std::string_view target) {
@@ -599,90 +664,72 @@
         ifs->bindPoints.erase(bindIt);
         l2.unlock();
         if (!savedFile.empty()) {
-            mIncFs->unlink(ifs->control, INCFS_ROOT_INODE, savedFile);
+            mIncFs->unlink(ifs->control, path::join(ifs->root, constants().mount, savedFile));
         }
     }
     return 0;
 }
 
-Inode IncrementalService::makeFile(StorageId storageId, std::string_view pathUnderStorage,
-                                   long size, std::string_view metadata,
-                                   std::string_view signature) {
-    (void)signature;
-    auto [parentInode, name] = parentAndNameFor(storageId, pathUnderStorage);
-    if (parentInode < 0) {
-        return -EINVAL;
-    }
-    if (auto ifs = getIfs(storageId)) {
-        auto inode = mIncFs->makeFile(ifs->control, name, parentInode, size, metadata);
-        if (inode < 0) {
-            return inode;
+int IncrementalService::makeFile(StorageId storage, std::string_view path, int mode, FileId id,
+                                 incfs::NewFileParams params) {
+    if (auto ifs = getIfs(storage)) {
+        auto err = mIncFs->makeFile(ifs->control, path, mode, id, params);
+        if (err) {
+            return err;
         }
-        auto metadataBytes = std::vector<uint8_t>();
-        if (metadata.data() != nullptr && metadata.size() > 0) {
-            metadataBytes.insert(metadataBytes.end(), &metadata.data()[0],
-                                 &metadata.data()[metadata.size()]);
+        std::vector<uint8_t> metadataBytes;
+        if (params.metadata.data && params.metadata.size > 0) {
+            metadataBytes.assign(params.metadata.data, params.metadata.data + params.metadata.size);
         }
-        mIncrementalManager->newFileForDataLoader(ifs->mountId, inode, metadataBytes);
-        return inode;
+        mIncrementalManager->newFileForDataLoader(ifs->mountId, id, metadataBytes);
+        return 0;
     }
     return -EINVAL;
 }
 
-Inode IncrementalService::makeDir(StorageId storageId, std::string_view pathUnderStorage,
-                                  std::string_view metadata) {
-    auto [parentInode, name] = parentAndNameFor(storageId, pathUnderStorage);
-    if (parentInode < 0) {
-        return -EINVAL;
-    }
+int IncrementalService::makeDir(StorageId storageId, std::string_view path, int mode) {
     if (auto ifs = getIfs(storageId)) {
-        return mIncFs->makeDir(ifs->control, name, parentInode, metadata);
+        return mIncFs->makeDir(ifs->control, path, mode);
     }
     return -EINVAL;
 }
 
-Inode IncrementalService::makeDirs(StorageId storageId, std::string_view pathUnderStorage,
-                                   std::string_view metadata) {
+int IncrementalService::makeDirs(StorageId storageId, std::string_view path, int mode) {
     const auto ifs = getIfs(storageId);
     if (!ifs) {
         return -EINVAL;
     }
-    std::string_view parentDir(pathUnderStorage);
-    auto p = parentAndNameFor(storageId, pathUnderStorage);
-    std::stack<std::string> pathsToCreate;
-    while (p.first < 0) {
-        parentDir = path::dirname(parentDir);
-        pathsToCreate.emplace(parentDir);
-        p = parentAndNameFor(storageId, parentDir);
+
+    auto err = mIncFs->makeDir(ifs->control, path, mode);
+    if (err == -EEXIST) {
+        return 0;
+    } else if (err != -ENOENT) {
+        return err;
     }
-    Inode inode;
-    while (!pathsToCreate.empty()) {
-        p = parentAndNameFor(storageId, pathsToCreate.top());
-        pathsToCreate.pop();
-        inode = mIncFs->makeDir(ifs->control, p.second, p.first, metadata);
-        if (inode < 0) {
-            return inode;
-        }
+    if (auto err = makeDirs(storageId, path::dirname(path), mode)) {
+        return err;
     }
-    return mIncFs->makeDir(ifs->control, path::basename(pathUnderStorage), inode, metadata);
+    return mIncFs->makeDir(ifs->control, path, mode);
 }
 
-int IncrementalService::link(StorageId storage, Inode item, Inode newParent,
-                             std::string_view newName) {
-    if (auto ifs = getIfs(storage)) {
-        return mIncFs->link(ifs->control, item, newParent, newName);
+int IncrementalService::link(StorageId sourceStorageId, std::string_view oldPath,
+                             StorageId destStorageId, std::string_view newPath) {
+    if (auto ifsSrc = getIfs(sourceStorageId), ifsDest = getIfs(destStorageId);
+        ifsSrc && ifsSrc == ifsDest) {
+        return mIncFs->link(ifsSrc->control, oldPath, newPath);
     }
     return -EINVAL;
 }
 
-int IncrementalService::unlink(StorageId storage, Inode parent, std::string_view name) {
+int IncrementalService::unlink(StorageId storage, std::string_view path) {
     if (auto ifs = getIfs(storage)) {
-        return mIncFs->unlink(ifs->control, parent, name);
+        return mIncFs->unlink(ifs->control, path);
     }
     return -EINVAL;
 }
 
-int IncrementalService::addBindMount(IncFsMount& ifs, StorageId storage, std::string&& sourceSubdir,
+int IncrementalService::addBindMount(IncFsMount& ifs, StorageId storage,
+                                     std::string_view storageRoot, std::string&& source,
                                      std::string&& target, BindKind kind,
                                      std::unique_lock<std::mutex>& mainLock) {
     if (!isValidMountTarget(target)) {
@@ -694,30 +741,30 @@
         metadata::BindPoint bp;
         bp.set_storage_id(storage);
         bp.set_allocated_dest_path(&target);
-        bp.set_allocated_source_subdir(&sourceSubdir);
+        bp.set_source_subdir(std::string(path::relativize(storageRoot, source)));
         const auto metadata = bp.SerializeAsString();
-        bp.release_source_subdir();
         bp.release_dest_path();
         mdFileName = makeBindMdName();
-        auto node = mIncFs->makeFile(ifs.control, mdFileName, INCFS_ROOT_INODE, 0, metadata);
-        if (node < 0) {
+        auto node =
+                mIncFs->makeFile(ifs.control, path::join(ifs.root, constants().mount, mdFileName),
+                                 0444, idFromMetadata(metadata),
+                                 {.metadata = {metadata.data(), (IncFsSize)metadata.size()}});
+        if (node) {
             return int(node);
         }
     }
 
-    return addBindMountWithMd(ifs, storage, std::move(mdFileName), std::move(sourceSubdir),
+    return addBindMountWithMd(ifs, storage, std::move(mdFileName), std::move(source),
                               std::move(target), kind, mainLock);
 }
 
 int IncrementalService::addBindMountWithMd(IncrementalService::IncFsMount& ifs, StorageId storage,
-                                           std::string&& metadataName, std::string&& sourceSubdir,
+                                           std::string&& metadataName, std::string&& source,
                                            std::string&& target, BindKind kind,
                                            std::unique_lock<std::mutex>& mainLock) {
-    LOG(INFO) << "Adding bind mount: " << sourceSubdir << " -> " << target;
     {
-        auto path = path::join(ifs.root, constants().mount, sourceSubdir);
         std::lock_guard l(mMountOperationLock);
-        const auto status = mVold->bindMount(path, target);
+        const auto status = mVold->bindMount(source, target);
         if (!status.isOk()) {
             LOG(ERROR) << "Calling Vold::bindMount() failed: " << status.toString8();
             return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC
@@ -736,12 +783,12 @@
     const auto [it, _] =
             ifs.bindPoints.insert_or_assign(target,
                                             IncFsMount::Bind{storage, std::move(metadataName),
-                                                             std::move(sourceSubdir), kind});
+                                                             std::move(source), kind});
     mBindsByPath[std::move(target)] = it;
     return 0;
 }
 
-RawMetadata IncrementalService::getMetadata(StorageId storage, Inode node) const {
+RawMetadata IncrementalService::getMetadata(StorageId storage, FileId node) const {
     const auto ifs = getIfs(storage);
     if (!ifs) {
         return {};
@@ -831,21 +878,18 @@
     LOG(INFO) << "Trying to mount: " << key;
 
     auto mountTarget = path::join(root, constants().mount);
-    const auto image = path::join(root, constants().backing, constants().image);
+    const auto backing = path::join(root, constants().backing);
 
     IncFsMount::Control control;
     IncrementalFileSystemControlParcel controlParcel;
-    auto status = mVold->mountIncFs(image, mountTarget, 0, &controlParcel);
+    auto status = mVold->mountIncFs(backing, mountTarget, 0, &controlParcel);
     if (!status.isOk()) {
         LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();
         return false;
     }
-    if (controlParcel.cmd) {
-        control.cmdFd = controlParcel.cmd->release();
-    }
-    if (controlParcel.log) {
-        control.logFd = controlParcel.log->release();
-    }
+    control.cmd = controlParcel.cmd.release().release();
+    control.pendingReads = controlParcel.pendingReads.release().release();
+    control.logs = controlParcel.log.release().release();
 
     auto ifs = std::make_shared<IncFsMount>(std::string(root), -1, std::move(control), *this);
 
@@ -860,8 +904,7 @@
     mNextId = std::max(mNextId, ifs->mountId + 1);
 
     std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints;
-    auto d = std::unique_ptr<DIR, decltype(&::closedir)>(::opendir(path::c_str(mountTarget)),
-                                                         ::closedir);
+    auto d = openDir(path::c_str(mountTarget));
     while (auto e = ::readdir(d.get())) {
         if (e->d_type == DT_REG) {
             auto name = std::string_view(e->d_name);
@@ -874,7 +917,7 @@
                 if (bindPoints.back().second.dest_path().empty() ||
                     bindPoints.back().second.source_subdir().empty()) {
                     bindPoints.pop_back();
-                    mIncFs->unlink(ifs->control, INCFS_ROOT_INODE, name);
+                    mIncFs->unlink(ifs->control, path::join(ifs->root, constants().mount, name));
                 }
             }
         } else if (e->d_type == DT_DIR) {
@@ -891,9 +934,7 @@
                                  << " for mount " << root;
                     continue;
                 }
-                ifs->storages.insert_or_assign(md.id(),
-                                               IncFsMount::Storage{std::string(name),
-                                                                   Inode(e->d_ino)});
+                ifs->storages.insert_or_assign(md.id(), IncFsMount::Storage{std::string(name)});
                 mNextId = std::max(mNextId, md.id() + 1);
             }
         }
@@ -973,10 +1014,10 @@
     }
     FileSystemControlParcel fsControlParcel;
     fsControlParcel.incremental = std::make_unique<IncrementalFileSystemControlParcel>();
-    fsControlParcel.incremental->cmd =
-            std::make_unique<os::ParcelFileDescriptor>(base::unique_fd(::dup(ifs.control.cmdFd)));
-    fsControlParcel.incremental->log =
-            std::make_unique<os::ParcelFileDescriptor>(base::unique_fd(::dup(ifs.control.logFd)));
+    fsControlParcel.incremental->cmd.reset(base::unique_fd(::dup(ifs.control.cmd)));
+    fsControlParcel.incremental->pendingReads.reset(
+            base::unique_fd(::dup(ifs.control.pendingReads)));
+    fsControlParcel.incremental->log.reset(base::unique_fd(::dup(ifs.control.logs)));
     sp<IncrementalDataLoaderListener> listener = new IncrementalDataLoaderListener(*this);
     bool created = false;
     auto status = mIncrementalManager->prepareDataLoader(ifs.mountId, fsControlParcel, *dlp,
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index a03ffa0..ca5e4db 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -52,16 +52,16 @@
 
 using MountId = int;
 using StorageId = int;
-using Inode = incfs::Inode;
+using FileId = incfs::FileId;
 using BlockIndex = incfs::BlockIndex;
 using RawMetadata = incfs::RawMetadata;
 using Clock = std::chrono::steady_clock;
 using TimePoint = std::chrono::time_point<Clock>;
 using Seconds = std::chrono::seconds;
 
-class IncrementalService {
+class IncrementalService final {
 public:
-    explicit IncrementalService(const ServiceManagerWrapper& sm, std::string_view rootDir);
+    explicit IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir);
 
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
@@ -85,6 +85,11 @@
         Permanent = 1,
     };
 
+    static FileId idFromMetadata(std::span<const uint8_t> metadata);
+    static inline FileId idFromMetadata(std::span<const char> metadata) {
+        return idFromMetadata({(const uint8_t*)metadata.data(), metadata.size()});
+    }
+
     std::optional<std::future<void>> onSystemReady();
 
     StorageId createStorage(std::string_view mountPoint,
@@ -92,30 +97,31 @@
                             CreateOptions options = CreateOptions::Default);
     StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage,
                                   CreateOptions options = CreateOptions::Default);
-    StorageId openStorage(std::string_view pathInMount);
+    StorageId openStorage(std::string_view path);
 
-    Inode nodeFor(StorageId storage, std::string_view subpath) const;
-    std::pair<Inode, std::string_view> parentAndNameFor(StorageId storage,
-                                                        std::string_view subpath) const;
+    FileId nodeFor(StorageId storage, std::string_view path) const;
+    std::pair<FileId, std::string_view> parentAndNameFor(StorageId storage,
+                                                         std::string_view path) const;
 
-    int bind(StorageId storage, std::string_view subdir, std::string_view target, BindKind kind);
+    int bind(StorageId storage, std::string_view source, std::string_view target, BindKind kind);
     int unbind(StorageId storage, std::string_view target);
     void deleteStorage(StorageId storage);
 
-    Inode makeFile(StorageId storage, std::string_view name, long size, std::string_view metadata,
-                   std::string_view signature);
-    Inode makeDir(StorageId storage, std::string_view name, std::string_view metadata = {});
-    Inode makeDirs(StorageId storage, std::string_view name, std::string_view metadata = {});
+    int makeFile(StorageId storage, std::string_view path, int mode, FileId id,
+                 incfs::NewFileParams params);
+    int makeDir(StorageId storage, std::string_view path, int mode = 0555);
+    int makeDirs(StorageId storage, std::string_view path, int mode = 0555);
 
-    int link(StorageId storage, Inode item, Inode newParent, std::string_view newName);
-    int unlink(StorageId storage, Inode parent, std::string_view name);
+    int link(StorageId sourceStorageId, std::string_view oldPath, StorageId destStorageId,
+             std::string_view newPath);
+    int unlink(StorageId storage, std::string_view path);
 
-    bool isRangeLoaded(StorageId storage, Inode file, std::pair<BlockIndex, BlockIndex> range) {
+    bool isRangeLoaded(StorageId storage, FileId file, std::pair<BlockIndex, BlockIndex> range) {
         return false;
     }
 
-    RawMetadata getMetadata(StorageId storage, Inode node) const;
-    std::string getSigngatureData(StorageId storage, Inode node) const { return {}; }
+    RawMetadata getMetadata(StorageId storage, FileId node) const;
+    std::string getSignatureData(StorageId storage, FileId node) const;
 
     std::vector<std::string> listFiles(StorageId storage) const;
     bool startLoading(StorageId storage) const;
@@ -142,19 +148,9 @@
 
         struct Storage {
             std::string name;
-            Inode node;
         };
 
-        struct Control {
-            operator IncFsControl() const { return {cmdFd, logFd}; }
-            void reset() {
-                cmdFd.reset();
-                logFd.reset();
-            }
-
-            base::unique_fd cmdFd;
-            base::unique_fd logFd;
-        };
+        using Control = incfs::UniqueControl;
 
         using BindMap = std::map<std::string, Bind>;
         using StorageMap = std::unordered_map<StorageId, Storage>;
@@ -196,11 +192,12 @@
 
     IfsMountPtr getIfs(StorageId storage) const;
     const IfsMountPtr& getIfsLocked(StorageId storage) const;
-    int addBindMount(IncFsMount& ifs, StorageId storage, std::string&& sourceSubdir,
-                     std::string&& target, BindKind kind, std::unique_lock<std::mutex>& mainLock);
+    int addBindMount(IncFsMount& ifs, StorageId storage, std::string_view storageRoot,
+                     std::string&& source, std::string&& target, BindKind kind,
+                     std::unique_lock<std::mutex>& mainLock);
 
     int addBindMountWithMd(IncFsMount& ifs, StorageId storage, std::string&& metadataName,
-                           std::string&& sourceSubdir, std::string&& target, BindKind kind,
+                           std::string&& source, std::string&& target, BindKind kind,
                            std::unique_lock<std::mutex>& mainLock);
 
     bool prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel* params);
@@ -212,10 +209,9 @@
     MountMap::iterator getStorageSlotLocked();
 
     // Member variables
-    // These are shared pointers for the sake of unit testing
-    std::shared_ptr<VoldServiceWrapper> mVold;
-    std::shared_ptr<IncrementalManagerWrapper> mIncrementalManager;
-    std::shared_ptr<IncFsWrapper> mIncFs;
+    std::unique_ptr<VoldServiceWrapper> mVold;
+    std::unique_ptr<IncrementalManagerWrapper> mIncrementalManager;
+    std::unique_ptr<IncFsWrapper> mIncFs;
     const std::string mIncrementalDir;
 
     mutable std::mutex mLock;
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index a79b26a..5d978a1 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -16,14 +16,8 @@
 
 #include "ServiceWrappers.h"
 
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <binder/IServiceManager.h>
 #include <utils/String16.h>
 
-#include <string>
-#include <string_view>
-
 using namespace std::literals;
 
 namespace android::os::incremental {
@@ -31,37 +25,38 @@
 static constexpr auto kVoldServiceName = "vold"sv;
 static constexpr auto kIncrementalManagerName = "incremental"sv;
 
-RealServiceManager::RealServiceManager(const sp<IServiceManager>& serviceManager)
-      : mServiceManager(serviceManager) {}
+RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager)
+      : mServiceManager(std::move(serviceManager)) {}
 
 template <class INTERFACE>
 sp<INTERFACE> RealServiceManager::getRealService(std::string_view serviceName) const {
-    sp<IBinder> binder = mServiceManager->getService(String16(serviceName.data()));
-    if (binder == 0) {
-        return 0;
+    sp<IBinder> binder =
+            mServiceManager->getService(String16(serviceName.data(), serviceName.size()));
+    if (!binder) {
+        return nullptr;
     }
     return interface_cast<INTERFACE>(binder);
 }
 
-std::shared_ptr<VoldServiceWrapper> RealServiceManager::getVoldService() const {
+std::unique_ptr<VoldServiceWrapper> RealServiceManager::getVoldService() {
     sp<os::IVold> vold = RealServiceManager::getRealService<os::IVold>(kVoldServiceName);
     if (vold != 0) {
-        return std::make_shared<RealVoldService>(vold);
+        return std::make_unique<RealVoldService>(vold);
     }
     return nullptr;
 }
 
-std::shared_ptr<IncrementalManagerWrapper> RealServiceManager::getIncrementalManager() const {
+std::unique_ptr<IncrementalManagerWrapper> RealServiceManager::getIncrementalManager() {
     sp<IIncrementalManager> manager =
             RealServiceManager::getRealService<IIncrementalManager>(kIncrementalManagerName);
-    if (manager != 0) {
-        return std::make_shared<RealIncrementalManager>(manager);
+    if (manager) {
+        return std::make_unique<RealIncrementalManager>(manager);
     }
     return nullptr;
 }
 
-std::shared_ptr<IncFsWrapper> RealServiceManager::getIncFs() const {
-    return std::make_shared<RealIncFs>();
+std::unique_ptr<IncFsWrapper> RealServiceManager::getIncFs() {
+    return std::make_unique<RealIncFs>();
 }
 
 } // namespace android::os::incremental
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 5704582..ae3739d 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -26,6 +26,7 @@
 #include <binder/IServiceManager.h>
 #include <incfs.h>
 
+#include <memory>
 #include <string>
 #include <string_view>
 
@@ -36,10 +37,12 @@
 
 // --- Wrapper interfaces ---
 
+using MountId = int32_t;
+
 class VoldServiceWrapper {
 public:
-    virtual ~VoldServiceWrapper(){};
-    virtual binder::Status mountIncFs(const std::string& imagePath, const std::string& targetDir,
+    virtual ~VoldServiceWrapper() = default;
+    virtual binder::Status mountIncFs(const std::string& backingPath, const std::string& targetDir,
                                       int32_t flags,
                                       IncrementalFileSystemControlParcel* _aidl_return) const = 0;
     virtual binder::Status unmountIncFs(const std::string& dir) const = 0;
@@ -49,52 +52,52 @@
 
 class IncrementalManagerWrapper {
 public:
-    virtual ~IncrementalManagerWrapper() {}
-    virtual binder::Status prepareDataLoader(
-            int32_t mountId, const FileSystemControlParcel& control,
-            const DataLoaderParamsParcel& params,
-            const sp<IDataLoaderStatusListener>& listener,
-            bool* _aidl_return) const = 0;
-    virtual binder::Status startDataLoader(int32_t mountId, bool* _aidl_return) const = 0;
-    virtual binder::Status destroyDataLoader(int32_t mountId) const = 0;
-    virtual binder::Status newFileForDataLoader(int32_t mountId, int64_t inode,
-                                                const ::std::vector<uint8_t>& metadata) const = 0;
-    virtual binder::Status showHealthBlockedUI(int32_t mountId) const = 0;
+    virtual ~IncrementalManagerWrapper() = default;
+    virtual binder::Status prepareDataLoader(MountId mountId,
+                                             const FileSystemControlParcel& control,
+                                             const DataLoaderParamsParcel& params,
+                                             const sp<IDataLoaderStatusListener>& listener,
+                                             bool* _aidl_return) const = 0;
+    virtual binder::Status startDataLoader(MountId mountId, bool* _aidl_return) const = 0;
+    virtual binder::Status destroyDataLoader(MountId mountId) const = 0;
+    virtual binder::Status newFileForDataLoader(MountId mountId, FileId fileid,
+                                                const std::vector<uint8_t>& metadata) const = 0;
+    virtual binder::Status showHealthBlockedUI(MountId mountId) const = 0;
 };
 
 class IncFsWrapper {
 public:
-    virtual ~IncFsWrapper() {}
-    virtual Inode makeFile(Control control, std::string_view name, Inode parent, Size size,
-                           std::string_view metadata) const = 0;
-    virtual Inode makeDir(Control control, std::string_view name, Inode parent,
-                          std::string_view metadata, int mode = 0555) const = 0;
-    virtual RawMetadata getMetadata(Control control, Inode inode) const = 0;
-    virtual ErrorCode link(Control control, Inode item, Inode targetParent,
-                           std::string_view name) const = 0;
-    virtual ErrorCode unlink(Control control, Inode parent, std::string_view name) const = 0;
-    virtual ErrorCode writeBlocks(Control control, const incfs_new_data_block blocks[],
-                                  int blocksCount) const = 0;
+    virtual ~IncFsWrapper() = default;
+    virtual ErrorCode makeFile(Control control, std::string_view path, int mode, FileId id,
+                               NewFileParams params) const = 0;
+    virtual ErrorCode makeDir(Control control, std::string_view path, int mode = 0555) const = 0;
+    virtual RawMetadata getMetadata(Control control, FileId fileid) const = 0;
+    virtual RawMetadata getMetadata(Control control, std::string_view path) const = 0;
+    virtual FileId getFileId(Control control, std::string_view path) const = 0;
+    virtual ErrorCode link(Control control, std::string_view from, std::string_view to) const = 0;
+    virtual ErrorCode unlink(Control control, std::string_view path) const = 0;
+    virtual base::unique_fd openWrite(Control control, FileId id) const = 0;
+    virtual ErrorCode writeBlocks(std::span<const DataBlock> blocks) const = 0;
 };
 
 class ServiceManagerWrapper {
 public:
-    virtual ~ServiceManagerWrapper() {}
-    virtual std::shared_ptr<VoldServiceWrapper> getVoldService() const = 0;
-    virtual std::shared_ptr<IncrementalManagerWrapper> getIncrementalManager() const = 0;
-    virtual std::shared_ptr<IncFsWrapper> getIncFs() const = 0;
+    virtual ~ServiceManagerWrapper() = default;
+    virtual std::unique_ptr<VoldServiceWrapper> getVoldService() = 0;
+    virtual std::unique_ptr<IncrementalManagerWrapper> getIncrementalManager() = 0;
+    virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0;
 };
 
 // --- Real stuff ---
 
 class RealVoldService : public VoldServiceWrapper {
 public:
-    RealVoldService(const sp<os::IVold> vold) : mInterface(vold) {}
+    RealVoldService(const sp<os::IVold> vold) : mInterface(std::move(vold)) {}
     ~RealVoldService() = default;
-    binder::Status mountIncFs(const std::string& imagePath, const std::string& targetDir,
+    binder::Status mountIncFs(const std::string& backingPath, const std::string& targetDir,
                               int32_t flags,
                               IncrementalFileSystemControlParcel* _aidl_return) const override {
-        return mInterface->mountIncFs(imagePath, targetDir, flags, _aidl_return);
+        return mInterface->mountIncFs(backingPath, targetDir, flags, _aidl_return);
     }
     binder::Status unmountIncFs(const std::string& dir) const override {
         return mInterface->unmountIncFs(dir);
@@ -113,24 +116,26 @@
     RealIncrementalManager(const sp<os::incremental::IIncrementalManager> manager)
           : mInterface(manager) {}
     ~RealIncrementalManager() = default;
-    binder::Status prepareDataLoader(
-            int32_t mountId, const FileSystemControlParcel& control,
-            const DataLoaderParamsParcel& params,
-            const sp<IDataLoaderStatusListener>& listener,
-            bool* _aidl_return) const override {
+    binder::Status prepareDataLoader(MountId mountId, const FileSystemControlParcel& control,
+                                     const DataLoaderParamsParcel& params,
+                                     const sp<IDataLoaderStatusListener>& listener,
+                                     bool* _aidl_return) const override {
         return mInterface->prepareDataLoader(mountId, control, params, listener, _aidl_return);
     }
-    binder::Status startDataLoader(int32_t mountId, bool* _aidl_return) const override {
+    binder::Status startDataLoader(MountId mountId, bool* _aidl_return) const override {
         return mInterface->startDataLoader(mountId, _aidl_return);
     }
-    binder::Status destroyDataLoader(int32_t mountId) const override {
+    binder::Status destroyDataLoader(MountId mountId) const override {
         return mInterface->destroyDataLoader(mountId);
     }
-    binder::Status newFileForDataLoader(int32_t mountId, int64_t inode,
-                                        const ::std::vector<uint8_t>& metadata) const override {
-        return mInterface->newFileForDataLoader(mountId, inode, metadata);
+    binder::Status newFileForDataLoader(MountId mountId, FileId fileid,
+                                        const std::vector<uint8_t>& metadata) const override {
+        return mInterface->newFileForDataLoader(mountId,
+                                                {(const uint8_t*)fileid.data,
+                                                 (const uint8_t*)fileid.data + sizeof(fileid.data)},
+                                                metadata);
     }
-    binder::Status showHealthBlockedUI(int32_t mountId) const override {
+    binder::Status showHealthBlockedUI(MountId mountId) const override {
         return mInterface->showHealthBlockedUI(mountId);
     }
 
@@ -140,11 +145,11 @@
 
 class RealServiceManager : public ServiceManagerWrapper {
 public:
-    RealServiceManager(const sp<IServiceManager>& serviceManager);
+    RealServiceManager(sp<IServiceManager> serviceManager);
     ~RealServiceManager() = default;
-    std::shared_ptr<VoldServiceWrapper> getVoldService() const override;
-    std::shared_ptr<IncrementalManagerWrapper> getIncrementalManager() const override;
-    std::shared_ptr<IncFsWrapper> getIncFs() const override;
+    std::unique_ptr<VoldServiceWrapper> getVoldService() override;
+    std::unique_ptr<IncrementalManagerWrapper> getIncrementalManager() override;
+    std::unique_ptr<IncFsWrapper> getIncFs() override;
 
 private:
     template <class INTERFACE>
@@ -156,27 +161,33 @@
 public:
     RealIncFs() = default;
     ~RealIncFs() = default;
-    Inode makeFile(Control control, std::string_view name, Inode parent, Size size,
-                   std::string_view metadata) const override {
-        return incfs::makeFile(control, name, parent, size, metadata);
+    ErrorCode makeFile(Control control, std::string_view path, int mode, FileId id,
+                       NewFileParams params) const override {
+        return incfs::makeFile(control, path, mode, id, params);
     }
-    Inode makeDir(Control control, std::string_view name, Inode parent, std::string_view metadata,
-                  int mode) const override {
-        return incfs::makeDir(control, name, parent, metadata, mode);
+    ErrorCode makeDir(Control control, std::string_view path, int mode) const override {
+        return incfs::makeDir(control, path, mode);
     }
-    RawMetadata getMetadata(Control control, Inode inode) const override {
-        return incfs::getMetadata(control, inode);
+    RawMetadata getMetadata(Control control, FileId fileid) const override {
+        return incfs::getMetadata(control, fileid);
     }
-    ErrorCode link(Control control, Inode item, Inode targetParent,
-                   std::string_view name) const override {
-        return incfs::link(control, item, targetParent, name);
+    RawMetadata getMetadata(Control control, std::string_view path) const override {
+        return incfs::getMetadata(control, path);
     }
-    ErrorCode unlink(Control control, Inode parent, std::string_view name) const override {
-        return incfs::unlink(control, parent, name);
+    FileId getFileId(Control control, std::string_view path) const override {
+        return incfs::getFileId(control, path);
     }
-    ErrorCode writeBlocks(Control control, const incfs_new_data_block blocks[],
-                          int blocksCount) const override {
-        return incfs::writeBlocks(control, blocks, blocksCount);
+    ErrorCode link(Control control, std::string_view from, std::string_view to) const override {
+        return incfs::link(control, from, to);
+    }
+    ErrorCode unlink(Control control, std::string_view path) const override {
+        return incfs::unlink(control, path);
+    }
+    base::unique_fd openWrite(Control control, FileId id) const override {
+        return base::unique_fd{incfs::openWrite(control, id)};
+    }
+    ErrorCode writeBlocks(std::span<const DataBlock> blocks) const override {
+        return incfs::writeBlocks(blocks);
     }
 };
 
diff --git a/services/incremental/path.cpp b/services/incremental/path.cpp
index c529d61..0d86f2a 100644
--- a/services/incremental/path.cpp
+++ b/services/incremental/path.cpp
@@ -44,16 +44,45 @@
                                         PathCharsLess());
 }
 
+static void preparePathComponent(std::string_view path, bool trimFront) {
+    if (trimFront) {
+        while (!path.empty() && path.front() == '/') {
+            path.remove_prefix(1);
+        }
+    }
+    while (!path.empty() && path.back() == '/') {
+        path.remove_suffix(1);
+    }
+}
+
 void details::append_next_path(std::string& target, std::string_view path) {
+    preparePathComponent(path, true);
     if (path.empty()) {
         return;
     }
-    if (!target.empty()) {
+    if (!target.empty() && !target.ends_with('/')) {
         target.push_back('/');
     }
     target += path;
 }
 
+std::string_view relativize(std::string_view parent, std::string_view nested) {
+    if (!nested.starts_with(parent)) {
+        return nested;
+    }
+    if (nested.size() == parent.size()) {
+        return {};
+    }
+    if (nested[parent.size()] != '/') {
+        return nested;
+    }
+    auto relative = nested.substr(parent.size());
+    while (relative.front() == '/') {
+        relative.remove_prefix(1);
+    }
+    return relative;
+}
+
 bool isAbsolute(std::string_view path) {
     return !path.empty() && path[0] == '/';
 }
diff --git a/services/incremental/path.h b/services/incremental/path.h
index a1f4b8e..3e5fd21 100644
--- a/services/incremental/path.h
+++ b/services/incremental/path.h
@@ -67,6 +67,20 @@
     return {sv};
 }
 
+std::string_view relativize(std::string_view parent, std::string_view nested);
+inline std::string_view relativize(const char* parent, const char* nested) {
+    return relativize(std::string_view(parent), std::string_view(nested));
+}
+inline std::string_view relativize(std::string_view parent, const char* nested) {
+    return relativize(parent, std::string_view(nested));
+}
+inline std::string_view relativize(const char* parent, std::string_view nested) {
+    return relativize(std::string_view(parent), nested);
+}
+
+std::string_view relativize(std::string&& parent, std::string_view nested) = delete;
+std::string_view relativize(std::string_view parent, std::string&& nested) = delete;
+
 bool isAbsolute(std::string_view path);
 std::string normalize(std::string_view path);
 std::string_view dirname(std::string_view path);
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index ca1e1a9..2826818 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -46,7 +46,7 @@
 class MockVoldService : public VoldServiceWrapper {
 public:
     MOCK_CONST_METHOD4(mountIncFs,
-                       binder::Status(const std::string& imagePath, const std::string& targetDir,
+                       binder::Status(const std::string& backingPath, const std::string& targetDir,
                                       int32_t flags,
                                       IncrementalFileSystemControlParcel* _aidl_return));
     MOCK_CONST_METHOD1(unmountIncFs, binder::Status(const std::string& dir));
@@ -77,22 +77,20 @@
     binder::Status getInvalidControlParcel(const std::string& imagePath,
                                            const std::string& targetDir, int32_t flags,
                                            IncrementalFileSystemControlParcel* _aidl_return) {
-        _aidl_return->cmd = nullptr;
-        _aidl_return->log = nullptr;
+        _aidl_return = {};
         return binder::Status::ok();
     }
     binder::Status incFsSuccess(const std::string& imagePath, const std::string& targetDir,
                                 int32_t flags, IncrementalFileSystemControlParcel* _aidl_return) {
-        _aidl_return->cmd = std::make_unique<os::ParcelFileDescriptor>(std::move(cmdFd));
-        _aidl_return->log = std::make_unique<os::ParcelFileDescriptor>(std::move(logFd));
+        _aidl_return->pendingReads.reset(base::unique_fd(dup(STDIN_FILENO)));
+        _aidl_return->cmd.reset(base::unique_fd(dup(STDIN_FILENO)));
+        _aidl_return->log.reset(base::unique_fd(dup(STDIN_FILENO)));
         return binder::Status::ok();
     }
 
 private:
     TemporaryFile cmdFile;
     TemporaryFile logFile;
-    base::unique_fd cmdFd;
-    base::unique_fd logFd;
 };
 
 class MockIncrementalManager : public IncrementalManagerWrapper {
@@ -105,7 +103,7 @@
     MOCK_CONST_METHOD2(startDataLoader, binder::Status(int32_t mountId, bool* _aidl_return));
     MOCK_CONST_METHOD1(destroyDataLoader, binder::Status(int32_t mountId));
     MOCK_CONST_METHOD3(newFileForDataLoader,
-                       binder::Status(int32_t mountId, int64_t inode,
+                       binder::Status(int32_t mountId, FileId fileId,
                                       const ::std::vector<uint8_t>& metadata));
     MOCK_CONST_METHOD1(showHealthBlockedUI, binder::Status(int32_t mountId));
 
@@ -152,23 +150,21 @@
 class MockIncFs : public IncFsWrapper {
 public:
     MOCK_CONST_METHOD5(makeFile,
-                       Inode(Control control, std::string_view name, Inode parent, Size size,
-                             std::string_view metadata));
-    MOCK_CONST_METHOD5(makeDir,
-                       Inode(Control control, std::string_view name, Inode parent,
-                             std::string_view metadata, int mode));
-    MOCK_CONST_METHOD2(getMetadata, RawMetadata(Control control, Inode inode));
-    MOCK_CONST_METHOD4(link,
-                       ErrorCode(Control control, Inode item, Inode targetParent,
-                                 std::string_view name));
-    MOCK_CONST_METHOD3(unlink, ErrorCode(Control control, Inode parent, std::string_view name));
-    MOCK_CONST_METHOD3(writeBlocks,
-                       ErrorCode(Control control, const incfs_new_data_block blocks[],
-                                 int blocksCount));
+                       ErrorCode(Control control, std::string_view path, int mode, FileId id,
+                                 NewFileParams params));
+    MOCK_CONST_METHOD3(makeDir, ErrorCode(Control control, std::string_view path, int mode));
+    MOCK_CONST_METHOD2(getMetadata, RawMetadata(Control control, FileId fileid));
+    MOCK_CONST_METHOD2(getMetadata, RawMetadata(Control control, std::string_view path));
+    MOCK_CONST_METHOD2(getFileId, FileId(Control control, std::string_view path));
+    MOCK_CONST_METHOD3(link,
+                       ErrorCode(Control control, std::string_view from, std::string_view to));
+    MOCK_CONST_METHOD2(unlink, ErrorCode(Control control, std::string_view path));
+    MOCK_CONST_METHOD2(openWrite, base::unique_fd(Control control, FileId id));
+    MOCK_CONST_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks));
 
     void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
     void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); }
-    RawMetadata getMountInfoMetadata(Control control, Inode inode) {
+    RawMetadata getMountInfoMetadata(Control control, std::string_view path) {
         metadata::Mount m;
         m.mutable_storage()->set_id(100);
         m.mutable_loader()->set_package_name("com.test");
@@ -176,15 +172,15 @@
         const auto metadata = m.SerializeAsString();
         m.mutable_loader()->release_arguments();
         m.mutable_loader()->release_package_name();
-        return std::vector<char>(metadata.begin(), metadata.end());
+        return {metadata.begin(), metadata.end()};
     }
-    RawMetadata getStorageMetadata(Control control, Inode inode) {
+    RawMetadata getStorageMetadata(Control control, std::string_view path) {
         metadata::Storage st;
         st.set_id(100);
         auto metadata = st.SerializeAsString();
-        return std::vector<char>(metadata.begin(), metadata.end());
+        return {metadata.begin(), metadata.end()};
     }
-    RawMetadata getBindPointMetadata(Control control, Inode inode) {
+    RawMetadata getBindPointMetadata(Control control, std::string_view path) {
         metadata::BindPoint bp;
         std::string destPath = "dest";
         std::string srcPath = "src";
@@ -200,40 +196,41 @@
 
 class MockServiceManager : public ServiceManagerWrapper {
 public:
-    MockServiceManager(std::shared_ptr<MockVoldService> vold,
-                       std::shared_ptr<MockIncrementalManager> manager,
-                       std::shared_ptr<MockIncFs> incfs)
-          : mVold(vold), mIncrementalManager(manager), mIncFs(incfs) {}
-    std::shared_ptr<VoldServiceWrapper> getVoldService() const override { return mVold; }
-    std::shared_ptr<IncrementalManagerWrapper> getIncrementalManager() const override {
-        return mIncrementalManager;
+    MockServiceManager(std::unique_ptr<MockVoldService> vold,
+                       std::unique_ptr<MockIncrementalManager> manager,
+                       std::unique_ptr<MockIncFs> incfs)
+          : mVold(std::move(vold)),
+            mIncrementalManager(std::move(manager)),
+            mIncFs(std::move(incfs)) {}
+    std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
+    std::unique_ptr<IncrementalManagerWrapper> getIncrementalManager() final {
+        return std::move(mIncrementalManager);
     }
-    std::shared_ptr<IncFsWrapper> getIncFs() const override { return mIncFs; }
+    std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); }
 
 private:
-    std::shared_ptr<MockVoldService> mVold;
-    std::shared_ptr<MockIncrementalManager> mIncrementalManager;
-    std::shared_ptr<MockIncFs> mIncFs;
+    std::unique_ptr<MockVoldService> mVold;
+    std::unique_ptr<MockIncrementalManager> mIncrementalManager;
+    std::unique_ptr<MockIncFs> mIncFs;
 };
 
 // --- IncrementalServiceTest ---
 
-static Inode inode(std::string_view path) {
-    struct stat st;
-    if (::stat(path::c_str(path), &st)) {
-        return -1;
-    }
-    return st.st_ino;
-}
-
 class IncrementalServiceTest : public testing::Test {
 public:
     void SetUp() override {
-        mVold = std::make_shared<NiceMock<MockVoldService>>();
-        mIncrementalManager = std::make_shared<NiceMock<MockIncrementalManager>>();
-        mIncFs = std::make_shared<NiceMock<MockIncFs>>();
-        MockServiceManager serviceManager = MockServiceManager(mVold, mIncrementalManager, mIncFs);
-        mIncrementalService = std::make_unique<IncrementalService>(serviceManager, mRootDir.path);
+        auto vold = std::make_unique<NiceMock<MockVoldService>>();
+        mVold = vold.get();
+        auto incrementalManager = std::make_unique<NiceMock<MockIncrementalManager>>();
+        mIncrementalManager = incrementalManager.get();
+        auto incFs = std::make_unique<NiceMock<MockIncFs>>();
+        mIncFs = incFs.get();
+        mIncrementalService =
+                std::make_unique<IncrementalService>(MockServiceManager(std::move(vold),
+                                                                        std::move(
+                                                                                incrementalManager),
+                                                                        std::move(incFs)),
+                                                     mRootDir.path);
         mDataLoaderParcel.packageName = "com.test";
         mDataLoaderParcel.arguments = "uri";
         mIncrementalService->onSystemReady();
@@ -252,20 +249,18 @@
         const auto mountPointsFile = rootDir + "/dir1/mount/.mountpoint.abcd";
         ASSERT_TRUE(base::WriteStringToFile("info", mountInfoFile));
         ASSERT_TRUE(base::WriteStringToFile("mounts", mountPointsFile));
-        ASSERT_GE(inode(mountInfoFile), 0);
-        ASSERT_GE(inode(mountPointsFile), 0);
-        ON_CALL(*mIncFs, getMetadata(_, inode(mountInfoFile)))
-                .WillByDefault(Invoke(mIncFs.get(), &MockIncFs::getMountInfoMetadata));
-        ON_CALL(*mIncFs, getMetadata(_, inode(mountPointsFile)))
-                .WillByDefault(Invoke(mIncFs.get(), &MockIncFs::getBindPointMetadata));
-        ON_CALL(*mIncFs, getMetadata(_, inode(rootDir + "/dir1/mount/st0")))
-                .WillByDefault(Invoke(mIncFs.get(), &MockIncFs::getStorageMetadata));
+        ON_CALL(*mIncFs, getMetadata(_, std::string_view(mountInfoFile)))
+                .WillByDefault(Invoke(mIncFs, &MockIncFs::getMountInfoMetadata));
+        ON_CALL(*mIncFs, getMetadata(_, std::string_view(mountPointsFile)))
+                .WillByDefault(Invoke(mIncFs, &MockIncFs::getBindPointMetadata));
+        ON_CALL(*mIncFs, getMetadata(_, std::string_view(rootDir + "/dir1/mount/st0")))
+                .WillByDefault(Invoke(mIncFs, &MockIncFs::getStorageMetadata));
     }
 
 protected:
-    std::shared_ptr<NiceMock<MockVoldService>> mVold;
-    std::shared_ptr<NiceMock<MockIncFs>> mIncFs;
-    std::shared_ptr<NiceMock<MockIncrementalManager>> mIncrementalManager;
+    NiceMock<MockVoldService>* mVold;
+    NiceMock<MockIncFs>* mIncFs;
+    NiceMock<MockIncrementalManager>* mIncrementalManager;
     std::unique_ptr<IncrementalService> mIncrementalService;
     TemporaryDir mRootDir;
     DataLoaderParamsParcel mDataLoaderParcel;
@@ -412,12 +407,12 @@
             mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
                                                IncrementalService::CreateOptions::CreateNew);
     std::string_view dir_path("test");
-    EXPECT_CALL(*mIncFs, makeDir(_, dir_path, _, _, _));
-    int fileIno = mIncrementalService->makeDir(storageId, dir_path, "");
-    ASSERT_GE(fileIno, 0);
+    EXPECT_CALL(*mIncFs, makeDir(_, dir_path, _));
+    auto res = mIncrementalService->makeDir(storageId, dir_path, 0555);
+    ASSERT_EQ(res, 0);
 }
 
-TEST_F(IncrementalServiceTest, testMakeDirectoryNoParent) {
+TEST_F(IncrementalServiceTest, testMakeDirectoryNested) {
     mVold->mountIncFsSuccess();
     mIncFs->makeFileSuccess();
     mVold->bindMountSuccess();
@@ -427,13 +422,15 @@
     int storageId =
             mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
                                                IncrementalService::CreateOptions::CreateNew);
-    std::string_view first("first");
-    std::string_view second("second");
+    auto first = "first"sv;
+    auto second = "second"sv;
     std::string dir_path = std::string(first) + "/" + std::string(second);
-    EXPECT_CALL(*mIncFs, makeDir(_, first, _, _, _)).Times(0);
-    EXPECT_CALL(*mIncFs, makeDir(_, second, _, _, _)).Times(0);
-    int fileIno = mIncrementalService->makeDir(storageId, dir_path, "");
-    ASSERT_LT(fileIno, 0);
+    EXPECT_CALL(*mIncFs, makeDir(_, first, _)).Times(0);
+    EXPECT_CALL(*mIncFs, makeDir(_, second, _)).Times(0);
+    EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(dir_path), _)).Times(1);
+
+    auto res = mIncrementalService->makeDir(storageId, dir_path, 0555);
+    ASSERT_EQ(res, 0);
 }
 
 TEST_F(IncrementalServiceTest, testMakeDirectories) {
@@ -446,16 +443,18 @@
     int storageId =
             mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
                                                IncrementalService::CreateOptions::CreateNew);
-    std::string_view first("first");
-    std::string_view second("second");
-    std::string_view third("third");
+    auto first = "first"sv;
+    auto second = "second"sv;
+    auto third = "third"sv;
     InSequence seq;
-    EXPECT_CALL(*mIncFs, makeDir(_, first, _, _, _));
-    EXPECT_CALL(*mIncFs, makeDir(_, second, _, _, _));
-    EXPECT_CALL(*mIncFs, makeDir(_, third, _, _, _));
-    std::string dir_path =
-            std::string(first) + "/" + std::string(second) + "/" + std::string(third);
-    int fileIno = mIncrementalService->makeDirs(storageId, dir_path, "");
-    ASSERT_GE(fileIno, 0);
+    auto parent_path = std::string(first) + "/" + std::string(second);
+    auto dir_path = parent_path + "/" + std::string(third);
+    EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(dir_path), _)).WillOnce(Return(-ENOENT));
+    EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(parent_path), _)).WillOnce(Return(-ENOENT));
+    EXPECT_CALL(*mIncFs, makeDir(_, first, _)).WillOnce(Return(0));
+    EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(parent_path), _)).WillOnce(Return(0));
+    EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(dir_path), _)).WillOnce(Return(0));
+    auto res = mIncrementalService->makeDirs(storageId, dir_path, 0555);
+    ASSERT_EQ(res, 0);
 }
 } // namespace android::os::incremental