diff options
author | 2020-01-10 11:53:24 -0800 | |
---|---|---|
committer | 2020-01-28 12:10:17 -0800 | |
commit | 4a25dfb2de3cf0f6dd81f4add3fd905db0834a38 (patch) | |
tree | fb36a044655007025be9e3fa8fb189281ac9698c | |
parent | 092993a72d710b7f5cb0f53aed736fd2675345e3 (diff) |
Port the current code to new IncFS
Bug: 146080380
Test: manual, "cmd incremental install-start"
Change-Id: I6761c3f0e58b6d4de1ae3c4b31c23204fba9f740
20 files changed, 821 insertions, 534 deletions
diff --git a/Android.bp b/Android.bp index 9411eeca834c..627681cb2280 100644 --- a/Android.bp +++ b/Android.bp @@ -922,6 +922,8 @@ filegroup { 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 17a310a5beb0..b415bc02fbcc 100644 --- a/core/java/android/os/incremental/IIncrementalManager.aidl +++ b/core/java/android/os/incremental/IIncrementalManager.aidl @@ -33,5 +33,7 @@ interface IIncrementalManager { 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 14215b1ea84d..2b6cd1478da8 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 @@ interface IIncrementalManagerNative { */ 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 @@ interface IIncrementalManagerNative { 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 63335a08f003..a0bfc1bf56b8 100644 --- a/core/java/android/os/incremental/IncrementalFileStorages.java +++ b/core/java/android/os/incremental/IncrementalFileStorages.java @@ -134,8 +134,8 @@ public final class IncrementalFileStorages { } 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 @@ public final class IncrementalFileStorages { 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 @@ public final class IncrementalFileStorages { 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 0ae353d2741f..6018ad1efc4a 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 000000000000..182732cebdf1 --- /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 000000000000..729e8e5556a8 --- /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 275086832c51..91dda0899a63 100644 --- a/core/java/android/os/incremental/IncrementalStorage.java +++ b/core/java/android/os/incremental/IncrementalStorage.java @@ -22,6 +22,8 @@ import android.os.RemoteException; 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 @@ public final class IncrementalStorage { * 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 @@ public final class IncrementalStorage { * 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 @@ public final class IncrementalStorage { /** * 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 @@ public final class IncrementalStorage { * 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 @@ public final class IncrementalStorage { /** * 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 @@ public final class IncrementalStorage { * 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 @@ public final class IncrementalStorage { * 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 @@ public final class IncrementalStorage { /** * 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 @@ public final class IncrementalStorage { /** * 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 @@ public final class IncrementalStorage { e.rethrowFromSystemServer(); } try { - mService.unlink(mId, sourcePathUnderStorage); + mService.unlink(mId, sourcepath); } catch (RemoteException ignored) { } } @@ -274,7 +289,7 @@ public final class IncrementalStorage { 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 @@ public final class IncrementalStorage { /** * 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 @@ public final class IncrementalStorage { /** * 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 path) { + try { + 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 String pathUnderStorage) { + public byte[] getFileMetadata(@NonNull UUID id) { try { - return mService.getFileMetadata(mId, pathUnderStorage); + 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 4e49302debcd..01150b773557 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 @@ struct RequestCommand { 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 @@ private: 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 @@ private: struct TracedRead { uint64_t timestampUs; - uint64_t fileIno; + android::dataloader::FileId fileId; uint32_t firstBlockIdx; uint32_t count; }; @@ -307,26 +305,26 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 d673ec84c47e..5876d433face 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 @@ public class IncrementalManagerService extends IIncrementalManager.Stub { // 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 ddf4dd53d5d3..323e7f156941 100644 --- a/services/incremental/Android.bp +++ b/services/incremental/Android.bp @@ -47,6 +47,8 @@ cc_defaults { shared_libs: [ "libandroidfw", "libbinder", + "libcrypto", + "libcutils", "libincfs", "liblog", "libz", diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp index bb26c1f93159..f1b637f516ea 100644 --- a/services/incremental/BinderIncrementalService.cpp +++ b/services/incremental/BinderIncrementalService.cpp @@ -46,10 +46,10 @@ static bool incFsEnabled() { 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 @@ BinderIncrementalService* BinderIncrementalService::start() { return nullptr; } sp<IVold> vold = interface_cast<IVold>(voldBinder); - if (!incFsVersionValid(vold)) { + if (!incFsValid(vold)) { return nullptr; } @@ -86,6 +86,7 @@ BinderIncrementalService* BinderIncrementalService::start() { 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 @@ binder::Status BinderIncrementalService::openStorage(const std::string& path, 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::createLinkedStorage(const std::string& } 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 @@ binder::Status BinderIncrementalService::deleteStorage(int32_t storageId) { 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) { +binder::Status BinderIncrementalService::makeFileFromRange(int32_t storageId, + const std::string& targetPath, + const std::string& sourcePath, + int64_t start, int64_t end, + int32_t* _aidl_return) { // TODO(b/136132412): implement this - *_aidl_return = -1; + *_aidl_return = ENOSYS; // not implemented return ok(); } + binder::Status BinderIncrementalService::makeLink(int32_t sourceStorageId, - const std::string& relativeSourcePath, + const std::string& sourcePath, int32_t destStorageId, - const std::string& relativeDestPath, + const std::string& destPath, 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); + *_aidl_return = mImpl.link(sourceStorageId, sourcePath, destStorageId, destPath); return ok(); } -binder::Status BinderIncrementalService::unlink(int32_t storageId, - const std::string& pathUnderStorage, + +binder::Status BinderIncrementalService::unlink(int32_t storageId, const std::string& path, int32_t* _aidl_return) { - auto [parentNode, name] = mImpl.parentAndNameFor(storageId, pathUnderStorage); - *_aidl_return = mImpl.unlink(storageId, parentNode, name); + *_aidl_return = mImpl.unlink(storageId, path); return ok(); } + binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId, - const std::string& relativePath, - int64_t start, int64_t end, - bool* _aidl_return) { + 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 37c9661db28d..a94a75a26875 100644 --- a/services/incremental/BinderIncrementalService.h +++ b/services/incremental/BinderIncrementalService.h @@ -37,38 +37,39 @@ public: 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 ¶ms, - 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 afce260ed41e..414c66c866db 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 @@ using IncrementalFileSystemControlParcel = 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 @@ template <base::LogSeverity level = base::ERROR> 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 @@ bool mkdirOrLog(std::string_view name, int mode = 0770, bool allowExisting = tru return false; } } + if (::chmod(cstr, mode)) { + PLOG(level) << "Changing permission failed for '" << name << '\''; + return false; + } + return true; } @@ -106,7 +112,7 @@ static std::pair<std::string, std::string> makeMountDir(std::string_view increme 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 @@ static std::pair<std::string, std::string> makeMountDir(std::string_view increme 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 @@ IncrementalService::IncFsMount::~IncFsMount() { } 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 @@ IncrementalService::IncrementalService(const ServiceManagerWrapper& sm, std::str // 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 @@ StorageId IncrementalService::createStorage(std::string_view mountPoint, 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 @@ StorageId IncrementalService::createStorage(std::string_view mountPoint, 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 @@ StorageId IncrementalService::createStorage(std::string_view mountPoint, 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 @@ StorageId IncrementalService::createStorage(std::string_view mountPoint, 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 @@ StorageId IncrementalService::createLinkedStorage(std::string_view mountPoint, 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 @@ StorageId IncrementalService::openStorage(std::string_view pathInMount) { 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 @@ const IncrementalService::IfsMountPtr& IncrementalService::getIfsLocked(StorageI 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 @@ int IncrementalService::bind(StorageId storage, std::string_view sourceSubdir, 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 @@ int IncrementalService::unbind(StorageId storage, std::string_view target) { 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); - } - 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; - } + + auto err = mIncFs->makeDir(ifs->control, path, mode); + if (err == -EEXIST) { + return 0; + } else if (err != -ENOENT) { + return err; + } + 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 @@ int IncrementalService::addBindMount(IncFsMount& ifs, StorageId storage, std::st 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 @@ int IncrementalService::addBindMountWithMd(IncrementalService::IncFsMount& ifs, 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 @@ bool IncrementalService::mountExistingImage(std::string_view root, std::string_v 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 @@ bool IncrementalService::mountExistingImage(std::string_view root, std::string_v 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 @@ bool IncrementalService::mountExistingImage(std::string_view root, std::string_v 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 @@ bool IncrementalService::mountExistingImage(std::string_view root, std::string_v << " 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 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, } 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 a03ffa00d035..ca5e4dbd9231 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -52,16 +52,16 @@ namespace android::incremental { 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 @@ public: 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 @@ public: 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 @@ private: 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 @@ private: 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 @@ private: 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 a79b26ae4fb3..5d978a1cf741 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 @@ namespace android::os::incremental { 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 570458283ac9..ae3739dba2f0 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 @@ namespace android::os::incremental { // --- 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 @@ public: 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 @@ public: 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 @@ private: 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 @@ class RealIncFs : public IncFsWrapper { 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); + } + ErrorCode makeDir(Control control, std::string_view path, int mode) const override { + return incfs::makeDir(control, path, mode); + } + RawMetadata getMetadata(Control control, FileId fileid) const override { + return incfs::getMetadata(control, fileid); + } + RawMetadata getMetadata(Control control, std::string_view path) const override { + return incfs::getMetadata(control, path); } - 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); + FileId getFileId(Control control, std::string_view path) const override { + return incfs::getFileId(control, path); } - RawMetadata getMetadata(Control control, Inode inode) const override { - return incfs::getMetadata(control, inode); + ErrorCode link(Control control, std::string_view from, std::string_view to) const override { + return incfs::link(control, from, to); } - ErrorCode link(Control control, Inode item, Inode targetParent, - std::string_view name) const override { - return incfs::link(control, item, targetParent, name); + ErrorCode unlink(Control control, std::string_view path) const override { + return incfs::unlink(control, path); } - ErrorCode unlink(Control control, Inode parent, std::string_view name) const override { - return incfs::unlink(control, parent, name); + base::unique_fd openWrite(Control control, FileId id) const override { + return base::unique_fd{incfs::openWrite(control, id)}; } - ErrorCode writeBlocks(Control control, const incfs_new_data_block blocks[], - int blocksCount) const override { - return incfs::writeBlocks(control, blocks, blocksCount); + 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 c529d61abd15..0d86f2a984d6 100644 --- a/services/incremental/path.cpp +++ b/services/incremental/path.cpp @@ -44,16 +44,45 @@ bool PathLess::operator()(std::string_view l, std::string_view r) const { 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 a1f4b8ec3093..3e5fd21b6535 100644 --- a/services/incremental/path.h +++ b/services/incremental/path.h @@ -67,6 +67,20 @@ inline details::CStrWrapper c_str(std::string_view sv) { 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 ca1e1a972047..28268181f173 100644 --- a/services/incremental/test/IncrementalServiceTest.cpp +++ b/services/incremental/test/IncrementalServiceTest.cpp @@ -46,7 +46,7 @@ namespace android::os::incremental { 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 @@ public: 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 @@ public: 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 @@ private: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ TEST_F(IncrementalServiceTest, testMakeDirectory) { 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 @@ TEST_F(IncrementalServiceTest, testMakeDirectoryNoParent) { 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 @@ TEST_F(IncrementalServiceTest, testMakeDirectories) { 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 |