Port the current code to new IncFS

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

Change-Id: I6761c3f0e58b6d4de1ae3c4b31c23204fba9f740
This commit is contained in:
Yurii Zubrytskyi
2020-01-10 11:53:24 -08:00
parent 092993a72d
commit 4a25dfb2de
20 changed files with 831 additions and 544 deletions

View File

@@ -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",
}

View File

@@ -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);
}

View File

@@ -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.

View File

@@ -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());
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 pathUnderStorage) {
public byte[] getFileMetadata(@NonNull String path) {
try {
return mService.getFileMetadata(mId, pathUnderStorage);
return mService.getMetadataByPath(mId, path);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
return null;
}
}
private static final int UUID_BYTE_SIZE = 16;
/**
* Converts UUID to a byte array usable for Incremental API calls
*
* @param id The id to convert
* @return Byte array that contains the same ID.
*/
public static byte[] idToBytes(UUID id) {
if (id == null) {
return null;
}
final ByteBuffer buf = ByteBuffer.wrap(new byte[UUID_BYTE_SIZE]);
buf.putLong(id.getMostSignificantBits());
buf.putLong(id.getLeastSignificantBits());
return buf.array();
}
/**
* Converts UUID from a byte array usable for Incremental API calls
*
* @param bytes The id in byte array format, 16 bytes long
* @return UUID constructed from the byte array.
*/
public static UUID bytesToId(byte[] bytes) {
if (bytes.length != UUID_BYTE_SIZE) {
throw new IllegalArgumentException("Expected array of size " + UUID_BYTE_SIZE
+ ", got " + bytes.length);
}
final ByteBuffer buf = ByteBuffer.wrap(bytes);
long msb = buf.getLong();
long lsb = buf.getLong();
return new UUID(msb, lsb);
}
/**
* Returns the metadata object of an IncFs File.
*
* @param id The file id.
* @return Byte array that contains metadata bytes.
*/
@Nullable
public byte[] getFileMetadata(@NonNull UUID id) {
try {
final byte[] rawId = idToBytes(id);
return mService.getMetadataById(mId, rawId);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
return null;

View File

@@ -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;

View File

@@ -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);

View File

@@ -47,6 +47,8 @@ cc_defaults {
shared_libs: [
"libandroidfw",
"libbinder",
"libcrypto",
"libcutils",
"libincfs",
"liblog",
"libz",

View File

@@ -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) {
// TODO(b/136132412): implement this
*_aidl_return = -1;
return ok();
}
binder::Status BinderIncrementalService::makeLink(int32_t sourceStorageId,
const std::string& relativeSourcePath,
int32_t destStorageId,
const std::string& relativeDestPath,
int32_t* _aidl_return) {
auto sourceInode = mImpl.nodeFor(sourceStorageId, relativeSourcePath);
auto [targetParentInode, name] = mImpl.parentAndNameFor(destStorageId, relativeDestPath);
*_aidl_return = mImpl.link(sourceStorageId, sourceInode, targetParentInode, name);
return ok();
}
binder::Status BinderIncrementalService::unlink(int32_t storageId,
const std::string& pathUnderStorage,
int32_t* _aidl_return) {
auto [parentNode, name] = mImpl.parentAndNameFor(storageId, pathUnderStorage);
*_aidl_return = mImpl.unlink(storageId, parentNode, name);
return ok();
}
binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId,
const std::string& relativePath,
binder::Status BinderIncrementalService::makeFileFromRange(int32_t storageId,
const std::string& targetPath,
const std::string& sourcePath,
int64_t start, int64_t end,
bool* _aidl_return) {
int32_t* _aidl_return) {
// TODO(b/136132412): implement this
*_aidl_return = ENOSYS; // not implemented
return ok();
}
binder::Status BinderIncrementalService::makeLink(int32_t sourceStorageId,
const std::string& sourcePath,
int32_t destStorageId,
const std::string& destPath,
int32_t* _aidl_return) {
*_aidl_return = mImpl.link(sourceStorageId, sourcePath, destStorageId, destPath);
return ok();
}
binder::Status BinderIncrementalService::unlink(int32_t storageId, const std::string& path,
int32_t* _aidl_return) {
*_aidl_return = mImpl.unlink(storageId, path);
return ok();
}
binder::Status BinderIncrementalService::isFileRangeLoaded(int32_t storageId,
const std::string& path, int64_t start,
int64_t end, bool* _aidl_return) {
// TODO: implement
*_aidl_return = false;
return ok();
}
binder::Status BinderIncrementalService::getFileMetadata(int32_t storageId,
const std::string& relativePath,
binder::Status BinderIncrementalService::getMetadataByPath(int32_t storageId,
const std::string& path,
std::vector<uint8_t>* _aidl_return) {
auto fid = mImpl.nodeFor(storageId, path);
if (fid != kIncFsInvalidFileId) {
auto metadata = mImpl.getMetadata(storageId, fid);
_aidl_return->assign(metadata.begin(), metadata.end());
}
return ok();
}
static FileId toFileId(const std::vector<uint8_t>& id) {
FileId fid;
memcpy(&fid, id.data(), id.size());
return fid;
}
binder::Status BinderIncrementalService::getMetadataById(int32_t storageId,
const std::vector<uint8_t>& id,
std::vector<uint8_t>* _aidl_return) {
auto inode = mImpl.nodeFor(storageId, relativePath);
auto metadata = mImpl.getMetadata(storageId, inode);
if (id.size() != sizeof(incfs::FileId)) {
return ok();
}
auto fid = toFileId(id);
auto metadata = mImpl.getMetadata(storageId, fid);
_aidl_return->assign(metadata.begin(), metadata.end());
return ok();
}
binder::Status BinderIncrementalService::makeDirectories(int32_t storageId, const std::string& path,
int32_t* _aidl_return) {
*_aidl_return = mImpl.makeDirs(storageId, path);
return ok();
}
binder::Status BinderIncrementalService::startLoading(int32_t storageId, bool* _aidl_return) {
*_aidl_return = mImpl.startLoading(storageId);
return ok();
}
} // namespace android::os::incremental
jlong Incremental_IncrementalService_Start() {

View File

@@ -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 &params,
int32_t createMode, int32_t *_aidl_return) final;
binder::Status createLinkedStorage(const std::string &path, int32_t otherStorageId,
int32_t createMode, int32_t *_aidl_return) final;
binder::Status makeBindMount(int32_t storageId, const std::string &pathUnderStorage,
const std::string &targetFullPath, int32_t bindType,
int32_t *_aidl_return) final;
binder::Status deleteBindMount(int32_t storageId, const std::string &targetFullPath,
int32_t *_aidl_return) final;
binder::Status openStorage(const std::string& path, int32_t* _aidl_return) final;
binder::Status createStorage(const std::string& path,
const ::android::content::pm::DataLoaderParamsParcel& params,
int32_t createMode, int32_t* _aidl_return) final;
binder::Status createLinkedStorage(const std::string& path, int32_t otherStorageId,
int32_t createMode, int32_t* _aidl_return) final;
binder::Status makeBindMount(int32_t storageId, const std::string& sourcePath,
const std::string& targetFullPath, int32_t bindType,
int32_t* _aidl_return) final;
binder::Status deleteBindMount(int32_t storageId, const std::string& targetFullPath,
int32_t* _aidl_return) final;
binder::Status makeDirectory(int32_t storageId, const std::string& path,
int32_t* _aidl_return) final;
binder::Status makeDirectories(int32_t storageId, const std::string& path,
int32_t* _aidl_return) final;
binder::Status makeFile(int32_t storageId, const std::string& path,
const ::android::os::incremental::IncrementalNewFileParams& params,
int32_t* _aidl_return) final;
binder::Status makeFileFromRange(int32_t storageId, const std::string& targetPath,
const std::string& sourcePath, int64_t start, int64_t end,
int32_t* _aidl_return) final;
binder::Status makeLink(int32_t sourceStorageId, const std::string& sourcePath,
int32_t destStorageId, const std::string& destPath,
int32_t* _aidl_return) final;
binder::Status unlink(int32_t storageId, const std::string& path, int32_t* _aidl_return) final;
binder::Status isFileRangeLoaded(int32_t storageId, const std::string& path, int64_t start,
int64_t end, bool* _aidl_return) final;
binder::Status getMetadataByPath(int32_t storageId, const std::string& path,
std::vector<uint8_t>* _aidl_return) final;
binder::Status getMetadataById(int32_t storageId, const std::vector<uint8_t>& id,
std::vector<uint8_t>* _aidl_return) final;
binder::Status startLoading(int32_t storageId, bool* _aidl_return) final;
binder::Status deleteStorage(int32_t storageId) final;
binder::Status makeDirectory(int32_t storageId, const std::string &pathUnderStorage,
int32_t *_aidl_return) final;
binder::Status makeDirectories(int32_t storageId, const std::string &pathUnderStorage,
int32_t *_aidl_return) final;
binder::Status makeFile(int32_t storageId, const std::string &pathUnderStorage, int64_t size,
const std::vector<uint8_t> &metadata, int32_t *_aidl_return) final;
binder::Status makeFileFromRange(int32_t storageId, const std::string &pathUnderStorage,
const std::string &sourcePathUnderStorage, int64_t start,
int64_t end, int32_t *_aidl_return);
binder::Status makeLink(int32_t sourceStorageId, const std::string &relativeSourcePath,
int32_t destStorageId, const std::string &relativeDestPath,
int32_t *_aidl_return) final;
binder::Status unlink(int32_t storageId, const std::string &pathUnderStorage,
int32_t *_aidl_return) final;
binder::Status isFileRangeLoaded(int32_t storageId, const std::string &relativePath,
int64_t start, int64_t end, bool *_aidl_return) final;
binder::Status getFileMetadata(int32_t storageId, const std::string &relativePath,
std::vector<uint8_t> *_aidl_return) final;
binder::Status startLoading(int32_t storageId, bool *_aidl_return) final;
private:
android::incremental::IncrementalService mImpl;

View File

@@ -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);
auto err = mIncFs->makeDir(ifs->control, path, mode);
if (err == -EEXIST) {
return 0;
} else if (err != -ENOENT) {
return err;
}
Inode inode;
while (!pathsToCreate.empty()) {
p = parentAndNameFor(storageId, pathsToCreate.top());
pathsToCreate.pop();
inode = mIncFs->makeDir(ifs->control, p.second, p.first, metadata);
if (inode < 0) {
return inode;
}
if (auto err = makeDirs(storageId, path::dirname(path), mode)) {
return err;
}
return mIncFs->makeDir(ifs->control, path::basename(pathUnderStorage), inode, metadata);
return mIncFs->makeDir(ifs->control, path, mode);
}
int IncrementalService::link(StorageId storage, Inode item, Inode newParent,
std::string_view newName) {
if (auto ifs = getIfs(storage)) {
return mIncFs->link(ifs->control, item, newParent, newName);
int IncrementalService::link(StorageId sourceStorageId, std::string_view oldPath,
StorageId destStorageId, std::string_view newPath) {
if (auto ifsSrc = getIfs(sourceStorageId), ifsDest = getIfs(destStorageId);
ifsSrc && ifsSrc == ifsDest) {
return mIncFs->link(ifsSrc->control, oldPath, newPath);
}
return -EINVAL;
}
int IncrementalService::unlink(StorageId storage, Inode parent, std::string_view name) {
int IncrementalService::unlink(StorageId storage, std::string_view path) {
if (auto ifs = getIfs(storage)) {
return mIncFs->unlink(ifs->control, parent, name);
return mIncFs->unlink(ifs->control, path);
}
return -EINVAL;
}
int IncrementalService::addBindMount(IncFsMount& ifs, StorageId storage, std::string&& sourceSubdir,
int IncrementalService::addBindMount(IncFsMount& ifs, StorageId storage,
std::string_view storageRoot, std::string&& source,
std::string&& target, BindKind kind,
std::unique_lock<std::mutex>& mainLock) {
if (!isValidMountTarget(target)) {
@@ -694,30 +741,30 @@ 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,

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}
Inode makeDir(Control control, std::string_view name, Inode parent, std::string_view metadata,
int mode) const override {
return incfs::makeDir(control, name, parent, metadata, mode);
ErrorCode makeDir(Control control, std::string_view path, int mode) const override {
return incfs::makeDir(control, path, mode);
}
RawMetadata getMetadata(Control control, Inode inode) const override {
return incfs::getMetadata(control, inode);
RawMetadata getMetadata(Control control, FileId fileid) const override {
return incfs::getMetadata(control, fileid);
}
ErrorCode link(Control control, Inode item, Inode targetParent,
std::string_view name) const override {
return incfs::link(control, item, targetParent, name);
RawMetadata getMetadata(Control control, std::string_view path) const override {
return incfs::getMetadata(control, path);
}
ErrorCode unlink(Control control, Inode parent, std::string_view name) const override {
return incfs::unlink(control, parent, name);
FileId getFileId(Control control, std::string_view path) const override {
return incfs::getFileId(control, path);
}
ErrorCode writeBlocks(Control control, const incfs_new_data_block blocks[],
int blocksCount) const override {
return incfs::writeBlocks(control, blocks, blocksCount);
ErrorCode link(Control control, std::string_view from, std::string_view to) const override {
return incfs::link(control, from, to);
}
ErrorCode unlink(Control control, std::string_view path) const override {
return incfs::unlink(control, path);
}
base::unique_fd openWrite(Control control, FileId id) const override {
return base::unique_fd{incfs::openWrite(control, id)};
}
ErrorCode writeBlocks(std::span<const DataBlock> blocks) const override {
return incfs::writeBlocks(blocks);
}
};

View File

@@ -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] == '/';
}

View File

@@ -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);

View File

@@ -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