Port the current code to new IncFS
Bug: 146080380 Test: manual, "cmd incremental install-start" Change-Id: I6761c3f0e58b6d4de1ae3c4b31c23204fba9f740
This commit is contained in:
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
31
core/java/android/os/incremental/IncrementalSignature.aidl
Normal file
31
core/java/android/os/incremental/IncrementalSignature.aidl
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -47,6 +47,8 @@ cc_defaults {
|
||||
shared_libs: [
|
||||
"libandroidfw",
|
||||
"libbinder",
|
||||
"libcrypto",
|
||||
"libcutils",
|
||||
"libincfs",
|
||||
"liblog",
|
||||
"libz",
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -37,38 +37,39 @@ public:
|
||||
void onSystemReady();
|
||||
void onInvalidStorage(int mountId);
|
||||
|
||||
binder::Status openStorage(const std::string &path, int32_t *_aidl_return) final;
|
||||
binder::Status createStorage(
|
||||
const std::string &path,
|
||||
const ::android::content::pm::DataLoaderParamsParcel ¶ms,
|
||||
int32_t createMode, int32_t *_aidl_return) final;
|
||||
binder::Status createLinkedStorage(const std::string &path, int32_t otherStorageId,
|
||||
int32_t createMode, int32_t *_aidl_return) final;
|
||||
binder::Status makeBindMount(int32_t storageId, const std::string &pathUnderStorage,
|
||||
const std::string &targetFullPath, int32_t bindType,
|
||||
int32_t *_aidl_return) final;
|
||||
binder::Status deleteBindMount(int32_t storageId, const std::string &targetFullPath,
|
||||
int32_t *_aidl_return) final;
|
||||
binder::Status openStorage(const std::string& path, int32_t* _aidl_return) final;
|
||||
binder::Status createStorage(const std::string& path,
|
||||
const ::android::content::pm::DataLoaderParamsParcel& params,
|
||||
int32_t createMode, int32_t* _aidl_return) final;
|
||||
binder::Status createLinkedStorage(const std::string& path, int32_t otherStorageId,
|
||||
int32_t createMode, int32_t* _aidl_return) final;
|
||||
binder::Status makeBindMount(int32_t storageId, const std::string& sourcePath,
|
||||
const std::string& targetFullPath, int32_t bindType,
|
||||
int32_t* _aidl_return) final;
|
||||
binder::Status deleteBindMount(int32_t storageId, const std::string& targetFullPath,
|
||||
int32_t* _aidl_return) final;
|
||||
binder::Status makeDirectory(int32_t storageId, const std::string& path,
|
||||
int32_t* _aidl_return) final;
|
||||
binder::Status makeDirectories(int32_t storageId, const std::string& path,
|
||||
int32_t* _aidl_return) final;
|
||||
binder::Status makeFile(int32_t storageId, const std::string& path,
|
||||
const ::android::os::incremental::IncrementalNewFileParams& params,
|
||||
int32_t* _aidl_return) final;
|
||||
binder::Status makeFileFromRange(int32_t storageId, const std::string& targetPath,
|
||||
const std::string& sourcePath, int64_t start, int64_t end,
|
||||
int32_t* _aidl_return) final;
|
||||
binder::Status makeLink(int32_t sourceStorageId, const std::string& sourcePath,
|
||||
int32_t destStorageId, const std::string& destPath,
|
||||
int32_t* _aidl_return) final;
|
||||
binder::Status unlink(int32_t storageId, const std::string& path, int32_t* _aidl_return) final;
|
||||
binder::Status isFileRangeLoaded(int32_t storageId, const std::string& path, int64_t start,
|
||||
int64_t end, bool* _aidl_return) final;
|
||||
binder::Status getMetadataByPath(int32_t storageId, const std::string& path,
|
||||
std::vector<uint8_t>* _aidl_return) final;
|
||||
binder::Status getMetadataById(int32_t storageId, const std::vector<uint8_t>& id,
|
||||
std::vector<uint8_t>* _aidl_return) final;
|
||||
binder::Status startLoading(int32_t storageId, bool* _aidl_return) final;
|
||||
binder::Status deleteStorage(int32_t storageId) final;
|
||||
binder::Status makeDirectory(int32_t storageId, const std::string &pathUnderStorage,
|
||||
int32_t *_aidl_return) final;
|
||||
binder::Status makeDirectories(int32_t storageId, const std::string &pathUnderStorage,
|
||||
int32_t *_aidl_return) final;
|
||||
binder::Status makeFile(int32_t storageId, const std::string &pathUnderStorage, int64_t size,
|
||||
const std::vector<uint8_t> &metadata, int32_t *_aidl_return) final;
|
||||
binder::Status makeFileFromRange(int32_t storageId, const std::string &pathUnderStorage,
|
||||
const std::string &sourcePathUnderStorage, int64_t start,
|
||||
int64_t end, int32_t *_aidl_return);
|
||||
binder::Status makeLink(int32_t sourceStorageId, const std::string &relativeSourcePath,
|
||||
int32_t destStorageId, const std::string &relativeDestPath,
|
||||
int32_t *_aidl_return) final;
|
||||
binder::Status unlink(int32_t storageId, const std::string &pathUnderStorage,
|
||||
int32_t *_aidl_return) final;
|
||||
binder::Status isFileRangeLoaded(int32_t storageId, const std::string &relativePath,
|
||||
int64_t start, int64_t end, bool *_aidl_return) final;
|
||||
binder::Status getFileMetadata(int32_t storageId, const std::string &relativePath,
|
||||
std::vector<uint8_t> *_aidl_return) final;
|
||||
binder::Status startLoading(int32_t storageId, bool *_aidl_return) final;
|
||||
|
||||
private:
|
||||
android::incremental::IncrementalService mImpl;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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] == '/';
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user