Incremental installations in PackageManagerShellCommand.
- onPrepareImage in native,
- allow to check installation type and choose native or managed
dataloaders,
- native data loader for Incremental,
- install-incremental shell command.
Test: atest PackageManagerShellCommandTest
Test: atest IncrementalServiceTest
Bug: b/136132412 b/133435829
Change-Id: I530a8a203fb50132c1869abd0b869036add18699
diff --git a/core/java/android/os/incremental/IIncrementalManager.aidl b/core/java/android/os/incremental/IIncrementalManager.aidl
index b415bc0..be83aae 100644
--- a/core/java/android/os/incremental/IIncrementalManager.aidl
+++ b/core/java/android/os/incremental/IIncrementalManager.aidl
@@ -33,7 +33,4 @@
boolean startDataLoader(int mountId);
void showHealthBlockedUI(int mountId);
void destroyDataLoader(int mountId);
-
- // fileId is a 16 byte long identifier.
- void newFileForDataLoader(int mountId, in byte[] fileId, in byte[] metadata);
}
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 9d98b3b..2dbaea8 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -17,6 +17,7 @@
package android.os.incremental;
import android.content.pm.DataLoaderParamsParcel;
+import android.content.pm.IDataLoaderStatusListener;
import android.os.incremental.IncrementalNewFileParams;
/** @hide */
@@ -33,7 +34,7 @@
* Opens or creates a storage given a target path and data loader params. Returns the storage ID.
*/
int openStorage(in @utf8InCpp String path);
- int createStorage(in @utf8InCpp String path, in DataLoaderParamsParcel params, int createMode);
+ int createStorage(in @utf8InCpp String path, in DataLoaderParamsParcel params, in IDataLoaderStatusListener listener, int createMode);
int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode);
/**
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 25fb3e0..3f8c0fe 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -35,6 +35,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.DataLoaderParams;
+import android.content.pm.IDataLoaderStatusListener;
import android.content.pm.InstallationFile;
import android.text.TextUtils;
import android.util.Slog;
@@ -74,6 +75,7 @@
public static IncrementalFileStorages initialize(Context context,
@NonNull File stageDir,
@NonNull DataLoaderParams dataLoaderParams,
+ @Nullable IDataLoaderStatusListener dataLoaderStatusListener,
List<InstallationFile> addedFiles) throws IOException {
// TODO(b/136132412): sanity check if session should not be incremental
IncrementalManager incrementalManager = (IncrementalManager) context.getSystemService(
@@ -85,7 +87,13 @@
IncrementalFileStorages result = null;
try {
- result = new IncrementalFileStorages(stageDir, incrementalManager, dataLoaderParams);
+ result = new IncrementalFileStorages(stageDir, incrementalManager, dataLoaderParams,
+ dataLoaderStatusListener);
+
+ if (!addedFiles.isEmpty()) {
+ result.mDefaultStorage.bind(stageDir.getAbsolutePath());
+ }
+
for (InstallationFile file : addedFiles) {
if (file.getLocation() == LOCATION_DATA_APP) {
try {
@@ -93,14 +101,15 @@
} catch (IOException e) {
// TODO(b/146080380): add incremental-specific error code
throw new IOException(
- "Failed to add and configure Incremental File: " + file.getName(),
- e);
+ "Failed to add file to IncFS: " + file.getName() + ", reason: "
+ + e.getMessage(), e.getCause());
}
} else {
throw new IOException("Unknown file location: " + file.getLocation());
}
}
+ // TODO(b/146080380): remove 5 secs wait in startLoading
if (!result.mDefaultStorage.startLoading()) {
// TODO(b/146080380): add incremental-specific error code
throw new IOException("Failed to start loading data for Incremental installation.");
@@ -117,7 +126,8 @@
private IncrementalFileStorages(@NonNull File stageDir,
@NonNull IncrementalManager incrementalManager,
- @NonNull DataLoaderParams dataLoaderParams) throws IOException {
+ @NonNull DataLoaderParams dataLoaderParams,
+ @Nullable IDataLoaderStatusListener dataLoaderStatusListener) throws IOException {
mStageDir = stageDir;
mIncrementalManager = incrementalManager;
if (dataLoaderParams.getComponentName().getPackageName().equals("local")) {
@@ -134,6 +144,7 @@
}
mDefaultStorage = mIncrementalManager.createStorage(mDefaultDir,
dataLoaderParams,
+ dataLoaderStatusListener,
IncrementalManager.CREATE_MODE_CREATE
| IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false);
}
@@ -144,10 +155,8 @@
}
private void addApkFile(@NonNull InstallationFile apk) throws IOException {
- final String stageDirPath = mStageDir.getAbsolutePath();
- mDefaultStorage.bind(stageDirPath);
- String apkName = apk.getName();
- File targetFile = Paths.get(stageDirPath, apkName).toFile();
+ final String apkName = apk.getName();
+ final File targetFile = new File(mStageDir, apkName);
if (!targetFile.exists()) {
mDefaultStorage.makeFile(apkName, apk.getLengthBytes(), null, apk.getMetadata(),
apk.getSignature());
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index d2d8f85..74a4215 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -22,6 +22,7 @@
import android.annotation.SystemService;
import android.content.Context;
import android.content.pm.DataLoaderParams;
+import android.content.pm.IDataLoaderStatusListener;
import android.os.RemoteException;
import android.util.SparseArray;
@@ -103,10 +104,11 @@
*/
@Nullable
public IncrementalStorage createStorage(@NonNull String path,
- @NonNull DataLoaderParams params, @CreateMode int createMode,
+ @NonNull DataLoaderParams params, @Nullable IDataLoaderStatusListener listener,
+ @CreateMode int createMode,
boolean autoStartDataLoader) {
try {
- final int id = mService.createStorage(path, params.getData(), createMode);
+ final int id = mService.createStorage(path, params.getData(), listener, createMode);
if (id < 0) {
return null;
}
diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java
index b9700b2..4190001 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -240,7 +240,7 @@
private native boolean nativeDestroyDataLoader(int storageId);
private native boolean nativePrepareImage(int storageId,
- Collection<InstallationFile> addedFiles, Collection<String> removedFiles);
+ List<InstallationFile> addedFiles, List<String> removedFiles);
private static native void nativeWriteData(long nativeInstance, String name, long offsetBytes,
long lengthBytes, ParcelFileDescriptor incomingFd);
diff --git a/core/jni/android_service_DataLoaderService.cpp b/core/jni/android_service_DataLoaderService.cpp
index b307a73..ed0d381 100644
--- a/core/jni/android_service_DataLoaderService.cpp
+++ b/core/jni/android_service_DataLoaderService.cpp
@@ -75,8 +75,9 @@
{"nativeStartDataLoader", "(I)Z", (void*)nativeStartDataLoader},
{"nativeStopDataLoader", "(I)Z", (void*)nativeStopDataLoader},
{"nativeDestroyDataLoader", "(I)Z", (void*)nativeDestroyDataLoader},
- {"nativePrepareImage", "(ILjava/util/Collection;Ljava/util/Collection;)Z", (void*)nativePrepareImage},
- {"nativeWriteData", "(JLjava/lang/String;JJLandroid/os/ParcelFileDescriptor;)V", (void*)nativeWriteData},
+ {"nativePrepareImage", "(ILjava/util/List;Ljava/util/List;)Z", (void*)nativePrepareImage},
+ {"nativeWriteData", "(JLjava/lang/String;JJLandroid/os/ParcelFileDescriptor;)V",
+ (void*)nativeWriteData},
};
} // namespace
diff --git a/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp b/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp
index 01150b7..6bd5a69 100644
--- a/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp
+++ b/packages/Incremental/NativeAdbDataLoader/jni/com_android_incremental_nativeadb_DataLoaderService.cpp
@@ -261,6 +261,11 @@
mReadLogFd.reset();
}
+ // Installation callback
+ bool onPrepareImage(const android::dataloader::DataLoaderInstallationFiles& addedFiles) final {
+ return true;
+ }
+
// IFS callbacks.
void onPendingReads(const android::dataloader::PendingReads& pendingReads) final {
std::lock_guard lock{mMapsMutex};
@@ -520,6 +525,6 @@
int JNI_OnLoad(JavaVM* jvm, void* /* reserved */) {
android::dataloader::DataLoader::initialize(
- [](auto) { return std::make_unique<AdbDataLoader>(); });
+ [](auto, auto) { return std::make_unique<AdbDataLoader>(); });
return JNI_VERSION_1_6;
}
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerService.java b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
index 64f25dd..a8121cc 100644
--- a/services/core/java/com/android/server/incremental/IncrementalManagerService.java
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
@@ -142,16 +142,6 @@
}
}
- // TODO: remove this
- @Override
- 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);
- return;
- }
- }
-
@Override
public void showHealthBlockedUI(int mountId) {
// TODO(b/136132412): implement this
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 97defcd..4ed4de7 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2450,17 +2450,6 @@
}
}
- // TODO(b/136132412): update with new APIs
- if (isIncrementalInstallation()) {
- try {
- mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext,
- stageDir, params.dataLoaderParams, addedFiles);
- return true;
- } catch (IOException e) {
- throw new PackageManagerException(e);
- }
- }
-
final DataLoaderManager dataLoaderManager = mContext.getSystemService(
DataLoaderManager.class);
if (dataLoaderManager == null) {
@@ -2468,6 +2457,7 @@
"Failed to find data loader manager service");
}
+ final boolean manualStartAndDestroy = !isIncrementalInstallation();
IDataLoaderStatusListener listener = new IDataLoaderStatusListener.Stub() {
@Override
public void onStatusChanged(int dataLoaderId, int status) {
@@ -2487,7 +2477,11 @@
switch (status) {
case IDataLoaderStatusListener.DATA_LOADER_CREATED: {
- dataLoader.start();
+ if (manualStartAndDestroy) {
+ // IncrementalFileStorages will call start after all files are
+ // created in IncFS.
+ dataLoader.start();
+ }
break;
}
case IDataLoaderStatusListener.DATA_LOADER_STARTED: {
@@ -2502,7 +2496,9 @@
} else {
dispatchStreamValidateAndCommit();
}
- dataLoader.destroy();
+ if (manualStartAndDestroy) {
+ dataLoader.destroy();
+ }
break;
}
case IDataLoaderStatusListener.DATA_LOADER_IMAGE_NOT_READY: {
@@ -2510,7 +2506,9 @@
onSessionVerificationFailure(
new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Failed to prepare image."));
- dataLoader.destroy();
+ if (manualStartAndDestroy) {
+ dataLoader.destroy();
+ }
break;
}
}
@@ -2524,6 +2522,17 @@
}
};
+ if (!manualStartAndDestroy) {
+ try {
+ mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext,
+ stageDir, params.dataLoaderParams, listener, addedFiles);
+ return false;
+ } catch (IOException e) {
+ throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(),
+ e.getCause());
+ }
+ }
+
final FileSystemConnector connector = new FileSystemConnector(addedFiles);
final FileSystemControlParcel control = new FileSystemControlParcel();
control.callback = connector;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index c69a62d..3909fdf 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -181,6 +181,8 @@
return runInstall();
case "install-streaming":
return runStreamingInstall();
+ case "install-incremental":
+ return runIncrementalInstall();
case "install-abandon":
case "install-destroy":
return runInstallAbandon();
@@ -1168,6 +1170,15 @@
return doRunInstall(params);
}
+ private int runIncrementalInstall() throws RemoteException {
+ final InstallParams params = makeInstallParams();
+ if (params.sessionParams.dataLoaderParams == null) {
+ params.sessionParams.setDataLoaderParams(
+ PackageManagerShellCommandDataLoader.getIncrementalDataLoaderParams(this));
+ }
+ return doRunInstall(params);
+ }
+
private int runInstall() throws RemoteException {
return doRunInstall(makeInstallParams());
}
@@ -3001,17 +3012,21 @@
return 1;
}
- session.addFile(LOCATION_DATA_APP, name, sizeBytes, STDIN_PATH_BYTES, null);
+ // Incremental requires unique metadatas, let's add a name to the dash.
+ session.addFile(LOCATION_DATA_APP, name, sizeBytes,
+ ("-" + name).getBytes(StandardCharsets.UTF_8), null);
continue;
}
// 3. Local file.
final String inPath = arg;
- String name = new File(inPath).getName();
+ final File file = new File(inPath);
+ final String name = file.getName();
+ final long size = file.length();
byte[] metadata = inPath.getBytes(StandardCharsets.UTF_8);
- session.addFile(LOCATION_DATA_APP, name, -1, metadata, null);
+ session.addFile(LOCATION_DATA_APP, name, size, metadata, null);
}
return 0;
} finally {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
index 4170be4..8f30e7d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.content.pm.DataLoaderParams;
import android.content.pm.InstallationFile;
+import android.content.pm.PackageInstaller;
import android.os.ParcelFileDescriptor;
import android.os.ShellCommand;
import android.service.dataloader.DataLoaderService;
@@ -55,6 +56,8 @@
private static final String STDIN_PATH = "-";
private static String getDataLoaderParamsArgs(ShellCommand shellCommand) {
+ nativeInitialize();
+
int commandId;
synchronized (sShellCommands) {
// Clean up old references.
@@ -86,6 +89,11 @@
getDataLoaderParamsArgs(shellCommand));
}
+ static DataLoaderParams getIncrementalDataLoaderParams(ShellCommand shellCommand) {
+ return DataLoaderParams.forIncremental(new ComponentName(PACKAGE, CLASS),
+ getDataLoaderParamsArgs(shellCommand), null);
+ }
+
private static int extractShellCommandId(String args) {
int sessionIdIdx = args.indexOf(SHELL_COMMAND_ID_PREFIX);
if (sessionIdIdx < 0) {
@@ -106,7 +114,7 @@
}
}
- static class DataLoader implements DataLoaderService.DataLoader {
+ private static class DataLoader implements DataLoaderService.DataLoader {
private DataLoaderParams mParams = null;
private FileSystemConnector mConnector = null;
@@ -121,17 +129,7 @@
@Override
public boolean onPrepareImage(@NonNull Collection<InstallationFile> addedFiles,
@NonNull Collection<String> removedFiles) {
- final int commandId = extractShellCommandId(mParams.getArguments());
- if (commandId == INVALID_SHELL_COMMAND_ID) {
- return false;
- }
-
- final WeakReference<ShellCommand> shellCommandRef;
- synchronized (sShellCommands) {
- shellCommandRef = sShellCommands.get(commandId, null);
- }
- final ShellCommand shellCommand =
- shellCommandRef != null ? shellCommandRef.get() : null;
+ ShellCommand shellCommand = lookupShellCommand(mParams.getArguments());
if (shellCommand == null) {
Slog.e(TAG, "Missing shell command.");
return false;
@@ -139,14 +137,13 @@
try {
for (InstallationFile file : addedFiles) {
String filePath = new String(file.getMetadata(), StandardCharsets.UTF_8);
- if (STDIN_PATH.equals(filePath) || TextUtils.isEmpty(filePath)) {
- final ParcelFileDescriptor inFd = ParcelFileDescriptor.dup(
- shellCommand.getInFileDescriptor());
+ if (TextUtils.isEmpty(filePath) || filePath.startsWith(STDIN_PATH)) {
+ final ParcelFileDescriptor inFd = getStdInPFD(shellCommand);
mConnector.writeData(file.getName(), 0, file.getLengthBytes(), inFd);
} else {
ParcelFileDescriptor incomingFd = null;
try {
- incomingFd = shellCommand.openFileForSystem(filePath, "r");
+ incomingFd = getLocalFile(shellCommand, filePath);
mConnector.writeData(file.getName(), 0, incomingFd.getStatSize(),
incomingFd);
} finally {
@@ -162,9 +159,45 @@
}
}
+ static ShellCommand lookupShellCommand(String args) {
+ final int commandId = extractShellCommandId(args);
+ if (commandId == INVALID_SHELL_COMMAND_ID) {
+ return null;
+ }
+
+ final WeakReference<ShellCommand> shellCommandRef;
+ synchronized (sShellCommands) {
+ shellCommandRef = sShellCommands.get(commandId, null);
+ }
+ final ShellCommand shellCommand =
+ shellCommandRef != null ? shellCommandRef.get() : null;
+
+ return shellCommand;
+ }
+
+ static ParcelFileDescriptor getStdInPFD(ShellCommand shellCommand) {
+ try {
+ return ParcelFileDescriptor.dup(shellCommand.getInFileDescriptor());
+ } catch (IOException e) {
+ Slog.e(TAG, "Exception while obtaining STDIN fd", e);
+ return null;
+ }
+ }
+
+ static ParcelFileDescriptor getLocalFile(ShellCommand shellCommand, String filePath) {
+ return shellCommand.openFileForSystem(filePath, "r");
+ }
+
@Override
public DataLoaderService.DataLoader onCreateDataLoader(
@NonNull DataLoaderParams dataLoaderParams) {
- return new DataLoader();
+ if (dataLoaderParams.getType() == PackageInstaller.DATA_LOADER_TYPE_STREAMING) {
+ // This DataLoader only supports streaming installations.
+ return new DataLoader();
+ }
+ return null;
}
+
+ /* Native methods */
+ private static native void nativeInitialize();
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 49c7e0a3..e888f2a 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -2,6 +2,7 @@
name: "libservices.core",
defaults: ["libservices.core-libs"],
+ cpp_std: "c++2a",
cflags: [
"-Wall",
"-Werror",
@@ -55,6 +56,7 @@
"com_android_server_am_CachedAppOptimizer.cpp",
"com_android_server_am_LowMemDetector.cpp",
"com_android_server_incremental_IncrementalManagerService.cpp",
+ "com_android_server_pm_PackageManagerShellCommandDataLoader.cpp",
"onload.cpp",
":lib_networkStatsFactory_native",
],
@@ -125,6 +127,8 @@
"libnetdbpf",
"libnetdutils",
"libpsi",
+ "libdataloader",
+ "libincfs",
"android.hardware.audio.common@2.0",
"android.hardware.broadcastradio@1.0",
"android.hardware.broadcastradio@1.1",
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
new file mode 100644
index 0000000..d803c1d
--- /dev/null
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -0,0 +1,327 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_ADB
+#define LOG_TAG "PackageManagerShellCommandDataLoader-jni"
+#include <android-base/logging.h>
+
+#include <android-base/unique_fd.h>
+#include <nativehelper/JNIHelp.h>
+
+#include <core_jni_helpers.h>
+
+#include "dataloader.h"
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+
+namespace {
+
+using android::base::unique_fd;
+
+static constexpr int BUFFER_SIZE = 256 * 1024;
+static constexpr int BLOCKS_COUNT = BUFFER_SIZE / INCFS_DATA_FILE_BLOCK_SIZE;
+
+struct JniIds {
+ jclass packageManagerShellCommandDataLoader;
+ jmethodID pmscdLookupShellCommand;
+ jmethodID pmscdGetStdInPFD;
+ jmethodID pmscdGetLocalFile;
+
+ jmethodID parcelFileDescriptorGetFileDescriptor;
+
+ jclass ioUtils;
+ jmethodID ioUtilsCloseQuietly;
+
+ JniIds(JNIEnv* env) {
+ packageManagerShellCommandDataLoader = (jclass)env->NewGlobalRef(
+ FindClassOrDie(env, "com/android/server/pm/PackageManagerShellCommandDataLoader"));
+ pmscdLookupShellCommand =
+ GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader,
+ "lookupShellCommand",
+ "(Ljava/lang/String;)Landroid/os/ShellCommand;");
+ pmscdGetStdInPFD =
+ GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader, "getStdInPFD",
+ "(Landroid/os/ShellCommand;)Landroid/os/"
+ "ParcelFileDescriptor;");
+ pmscdGetLocalFile =
+ GetStaticMethodIDOrDie(env, packageManagerShellCommandDataLoader, "getLocalFile",
+ "(Landroid/os/ShellCommand;Ljava/lang/String;)Landroid/os/"
+ "ParcelFileDescriptor;");
+
+ auto parcelFileDescriptor = FindClassOrDie(env, "android/os/ParcelFileDescriptor");
+ parcelFileDescriptorGetFileDescriptor =
+ GetMethodIDOrDie(env, parcelFileDescriptor, "getFileDescriptor",
+ "()Ljava/io/FileDescriptor;");
+
+ ioUtils = (jclass)env->NewGlobalRef(FindClassOrDie(env, "libcore/io/IoUtils"));
+ ioUtilsCloseQuietly = GetStaticMethodIDOrDie(env, ioUtils, "closeQuietly",
+ "(Ljava/lang/AutoCloseable;)V");
+ }
+};
+
+const JniIds& jniIds(JNIEnv* env) {
+ static const JniIds ids(env);
+ return ids;
+}
+
+static inline unique_fd convertPfdToFdAndDup(JNIEnv* env, const JniIds& jni, jobject pfd) {
+ if (!pfd) {
+ ALOGE("Missing In ParcelFileDescriptor.");
+ return {};
+ }
+ auto managedFd = env->CallObjectMethod(pfd, jni.parcelFileDescriptorGetFileDescriptor);
+ if (!pfd) {
+ ALOGE("Missing In FileDescriptor.");
+ return {};
+ }
+ return unique_fd{dup(jniGetFDFromFileDescriptor(env, managedFd))};
+}
+
+static inline std::pair<unique_fd, bool> openIncomingFile(JNIEnv* env, const JniIds& jni,
+ jobject shellCommand,
+ IncFsSpan metadata) {
+ jobject pfd = nullptr;
+ const bool stdin = (metadata.size == 0 || *metadata.data == '-');
+ if (stdin) {
+ // stdin
+ pfd = env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader,
+ jni.pmscdGetStdInPFD, shellCommand);
+ } else {
+ // file
+ const std::string filePath(metadata.data, metadata.size);
+ pfd = env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader,
+ jni.pmscdGetLocalFile, shellCommand,
+ env->NewStringUTF(filePath.c_str()));
+ }
+
+ auto result = convertPfdToFdAndDup(env, jni, pfd);
+ if (pfd) {
+ // Can be closed after dup.
+ env->CallStaticVoidMethod(jni.ioUtils, jni.ioUtilsCloseQuietly, pfd);
+ }
+
+ return {std::move(result), stdin};
+}
+
+static inline JNIEnv* GetJNIEnvironment(JavaVM* vm) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ return 0;
+ }
+ return env;
+}
+
+static inline JNIEnv* GetOrAttachJNIEnvironment(JavaVM* jvm) {
+ JNIEnv* env = GetJNIEnvironment(jvm);
+ if (!env) {
+ int result = jvm->AttachCurrentThread(&env, nullptr);
+ CHECK_EQ(result, JNI_OK) << "thread attach failed";
+ struct VmDetacher {
+ VmDetacher(JavaVM* vm) : mVm(vm) {}
+ ~VmDetacher() { mVm->DetachCurrentThread(); }
+
+ private:
+ JavaVM* const mVm;
+ };
+ static thread_local VmDetacher detacher(jvm);
+ }
+ return env;
+}
+
+class PackageManagerShellCommandDataLoaderDataLoader : public android::dataloader::DataLoader {
+public:
+ PackageManagerShellCommandDataLoaderDataLoader(JavaVM* jvm) : mJvm(jvm) { CHECK(mJvm); }
+
+private:
+ // Lifecycle.
+ bool onCreate(const android::dataloader::DataLoaderParams& params,
+ android::dataloader::FilesystemConnectorPtr ifs,
+ android::dataloader::StatusListenerPtr statusListener,
+ android::dataloader::ServiceConnectorPtr,
+ android::dataloader::ServiceParamsPtr) final {
+ mArgs = params.arguments();
+ mIfs = ifs;
+ return true;
+ }
+ bool onStart() final { return true; }
+ void onStop() final {}
+ void onDestroy() final {}
+
+ // IFS callbacks.
+ void onPendingReads(const dataloader::PendingReads& pendingReads) final {}
+ void onPageReads(const dataloader::PageReads& pageReads) final {}
+
+ // FS callbacks.
+ bool onPrepareImage(const dataloader::DataLoaderInstallationFiles& addedFiles) final {
+ JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
+ const auto& jni = jniIds(env);
+
+ jobject shellCommand = env->CallStaticObjectMethod(jni.packageManagerShellCommandDataLoader,
+ jni.pmscdLookupShellCommand,
+ env->NewStringUTF(mArgs.c_str()));
+ if (!shellCommand) {
+ ALOGE("Missing shell command.");
+ return false;
+ }
+
+ std::vector<char> buffer;
+ buffer.reserve(BUFFER_SIZE);
+
+ std::vector<IncFsDataBlock> blocks;
+ blocks.reserve(BLOCKS_COUNT);
+
+ for (auto&& file : addedFiles) {
+ auto [incomingFd, stdin] = openIncomingFile(env, jni, shellCommand, file.metadata);
+ if (incomingFd < 0) {
+ ALOGE("Failed to open an IncFS file for metadata: %.*s, final file name is: %s. "
+ "Error %d",
+ int(file.metadata.size), file.metadata.data, file.name, errno);
+ return false;
+ }
+
+ const auto fileId = IncFs_FileIdFromMetadata(file.metadata);
+
+ const auto incfsFd(mIfs->openWrite(fileId));
+ if (incfsFd < 0) {
+ ALOGE("Failed to open an IncFS file for metadata: %.*s, final file name is: %s. "
+ "Error %d",
+ int(file.metadata.size), file.metadata.data, file.name, errno);
+ return false;
+ }
+
+ IncFsSize size = file.size;
+ IncFsSize remaining = size;
+ IncFsSize totalSize = 0;
+ IncFsBlockIndex blockIdx = 0;
+ while (remaining > 0) {
+ constexpr auto capacity = BUFFER_SIZE;
+ auto size = buffer.size();
+ if (capacity - size < INCFS_DATA_FILE_BLOCK_SIZE) {
+ if (!flashToIncFs(incfsFd, false, &blocks, &blockIdx, &buffer)) {
+ return false;
+ }
+ continue;
+ }
+
+ auto toRead = std::min<IncFsSize>(remaining, capacity - size);
+ buffer.resize(size + toRead);
+ auto read = ::read(incomingFd, buffer.data() + size, toRead);
+ if (read == 0) {
+ if (stdin) {
+ // eof of stdin, waiting...
+ ALOGE("eof of stdin, waiting...: %d, remaining: %d, block: %d, read: %d",
+ int(totalSize), int(remaining), int(blockIdx), int(read));
+ using namespace std::chrono_literals;
+ std::this_thread::sleep_for(10ms);
+ continue;
+ }
+ break;
+ }
+ if (read < 0) {
+ ALOGE("Underlying file read error: %.*s: %d", int(file.metadata.size),
+ file.metadata.data, int(read));
+ return false;
+ }
+
+ buffer.resize(size + read);
+ remaining -= read;
+ totalSize += read;
+ }
+ if (!buffer.empty() && !flashToIncFs(incfsFd, true, &blocks, &blockIdx, &buffer)) {
+ return false;
+ }
+ }
+
+ ALOGE("All done.");
+ return true;
+ }
+
+ bool flashToIncFs(int incfsFd, bool eof, std::vector<IncFsDataBlock>* blocks,
+ IncFsBlockIndex* blockIdx, std::vector<char>* buffer) {
+ int consumed = 0;
+ const auto fullBlocks = buffer->size() / INCFS_DATA_FILE_BLOCK_SIZE;
+ for (int i = 0; i < fullBlocks; ++i) {
+ const auto inst = IncFsDataBlock{
+ .fileFd = incfsFd,
+ .pageIndex = (*blockIdx)++,
+ .compression = INCFS_COMPRESSION_KIND_NONE,
+ .kind = INCFS_BLOCK_KIND_DATA,
+ .dataSize = INCFS_DATA_FILE_BLOCK_SIZE,
+ .data = buffer->data() + consumed,
+ };
+ blocks->push_back(inst);
+ consumed += INCFS_DATA_FILE_BLOCK_SIZE;
+ }
+ const auto remain = buffer->size() - fullBlocks * INCFS_DATA_FILE_BLOCK_SIZE;
+ if (remain && eof) {
+ const auto inst = IncFsDataBlock{
+ .fileFd = incfsFd,
+ .pageIndex = (*blockIdx)++,
+ .compression = INCFS_COMPRESSION_KIND_NONE,
+ .kind = INCFS_BLOCK_KIND_DATA,
+ .dataSize = static_cast<uint16_t>(remain),
+ .data = buffer->data() + consumed,
+ };
+ blocks->push_back(inst);
+ consumed += remain;
+ }
+
+ auto res = mIfs->writeBlocks({blocks->data(), blocks->data() + blocks->size()});
+
+ blocks->clear();
+ buffer->erase(buffer->begin(), buffer->begin() + consumed);
+
+ if (res < 0) {
+ ALOGE("Failed to write block to IncFS: %d", int(res));
+ return false;
+ }
+ return true;
+ }
+
+ JavaVM* const mJvm;
+ std::string mArgs;
+ android::dataloader::FilesystemConnectorPtr mIfs;
+};
+
+static void nativeInitialize(JNIEnv* env, jclass klass) {
+ jniIds(env);
+}
+
+static const JNINativeMethod method_table[] = {
+ {"nativeInitialize", "()V", (void*)nativeInitialize},
+};
+
+} // namespace
+
+int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(
+ JNIEnv* env) {
+ android::dataloader::DataLoader::initialize(
+ [](auto jvm, const auto& params) -> android::dataloader::DataLoaderPtr {
+ if (params.type() == DATA_LOADER_TYPE_INCREMENTAL) {
+ // This DataLoader only supports incremental installations.
+ return std::make_unique<PackageManagerShellCommandDataLoaderDataLoader>(jvm);
+ }
+ return {};
+ });
+ return jniRegisterNativeMethods(env,
+ "com/android/server/pm/PackageManagerShellCommandDataLoader",
+ method_table, NELEM(method_table));
+}
+
+} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index c186494..e575432 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -59,6 +59,7 @@
int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
JNIEnv* env);
int register_android_server_incremental_IncrementalManagerService(JNIEnv* env);
+int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(JNIEnv* env);
int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
};
@@ -112,6 +113,7 @@
register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
env);
register_android_server_incremental_IncrementalManagerService(env);
+ register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(env);
register_android_server_stats_pull_StatsPullAtomService(env);
return JNI_VERSION_1_4;
}
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index b2c316a..3fcb57a 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -117,10 +117,9 @@
binder::Status BinderIncrementalService::createStorage(const std::string& path,
const DataLoaderParamsParcel& params,
+ const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener,
int32_t createMode, int32_t* _aidl_return) {
- *_aidl_return = mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params),
- android::incremental::IncrementalService::CreateOptions(
- createMode));
+ *_aidl_return = mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params), listener, android::incremental::IncrementalService::CreateOptions(createMode));
return ok();
}
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 51d7de3..4075da6 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -38,9 +38,7 @@
void onInvalidStorage(int mountId);
binder::Status openStorage(const std::string& path, int32_t* _aidl_return) final;
- binder::Status createStorage(const std::string& path,
- const ::android::content::pm::DataLoaderParamsParcel& params,
- int32_t createMode, int32_t* _aidl_return) final;
+ binder::Status createStorage(const ::std::string& path, const ::android::content::pm::DataLoaderParamsParcel& params, const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener, 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,
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 3b51377..ebadf56 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -30,7 +30,6 @@
#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>
@@ -242,20 +241,7 @@
}
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;
+ return IncFs_FileIdFromMetadata({(const char*)metadata.data(), metadata.size()});
}
IncrementalService::~IncrementalService() = default;
@@ -344,7 +330,7 @@
std::thread([this, mounts = std::move(mounts)]() {
std::vector<IfsMountPtr> failedLoaderMounts;
for (auto&& ifs : mounts) {
- if (prepareDataLoader(*ifs, nullptr)) {
+ if (prepareDataLoader(*ifs)) {
LOG(INFO) << "Successfully started data loader for mount " << ifs->mountId;
} else {
LOG(WARNING) << "Failed to start data loader for mount " << ifs->mountId;
@@ -377,6 +363,7 @@
StorageId IncrementalService::createStorage(std::string_view mountPoint,
DataLoaderParamsParcel&& dataLoaderParams,
+ const DataLoaderStatusListener& dataLoaderStatusListener,
CreateOptions options) {
LOG(INFO) << "createStorage: " << mountPoint << " | " << int(options);
if (!path::isAbsolute(mountPoint)) {
@@ -509,7 +496,7 @@
// Done here as well, all data structures are in good state.
secondCleanupOnFailure.release();
- if (!prepareDataLoader(*ifs, &dataLoaderParams)) {
+ if (!prepareDataLoader(*ifs, &dataLoaderParams, &dataLoaderStatusListener)) {
LOG(ERROR) << "prepareDataLoader() failed";
deleteStorageLocked(*ifs, std::move(l));
return kInvalidStorageId;
@@ -767,7 +754,6 @@
if (params.metadata.data && params.metadata.size > 0) {
metadataBytes.assign(params.metadata.data, params.metadata.data + params.metadata.size);
}
- mIncrementalManager->newFileForDataLoader(ifs->mountId, id, metadataBytes);
return 0;
}
return -EINVAL;
@@ -1074,7 +1060,8 @@
}
bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs,
- DataLoaderParamsParcel* params) {
+ DataLoaderParamsParcel* params,
+ const DataLoaderStatusListener* externalListener) {
if (!mSystemReady.load(std::memory_order_relaxed)) {
std::unique_lock l(ifs.lock);
if (params) {
@@ -1117,7 +1104,7 @@
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);
+ sp<IncrementalDataLoaderListener> listener = new IncrementalDataLoaderListener(*this, *externalListener);
bool created = false;
auto status = mIncrementalManager->prepareDataLoader(ifs.mountId, fsControlParcel, *dlp,
listener, &created);
@@ -1247,6 +1234,11 @@
binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId,
int newStatus) {
+ if (externalListener) {
+ // Give an external listener a chance to act before we destroy something.
+ externalListener->onStatusChanged(mountId, newStatus);
+ }
+
std::unique_lock l(incrementalService.mLock);
const auto& ifs = incrementalService.getIfsLocked(mountId);
if (!ifs) {
@@ -1288,6 +1280,12 @@
case IDataLoaderStatusListener::DATA_LOADER_STOPPED: {
break;
}
+ case IDataLoaderStatusListener::DATA_LOADER_IMAGE_READY: {
+ break;
+ }
+ case IDataLoaderStatusListener::DATA_LOADER_IMAGE_NOT_READY: {
+ break;
+ }
default: {
LOG(WARNING) << "Unknown data loader status: " << newStatus
<< " for mount: " << mountId;
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 2e7ced3..75d066b 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -59,6 +59,8 @@
using TimePoint = std::chrono::time_point<Clock>;
using Seconds = std::chrono::seconds;
+using DataLoaderStatusListener = ::android::sp<::android::content::pm::IDataLoaderStatusListener>;
+
class IncrementalService final {
public:
explicit IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir);
@@ -94,7 +96,9 @@
std::optional<std::future<void>> onSystemReady();
- StorageId createStorage(std::string_view mountPoint, DataLoaderParamsParcel&& dataLoaderParams,
+ StorageId createStorage(std::string_view mountPoint,
+ DataLoaderParamsParcel&& dataLoaderParams,
+ const DataLoaderStatusListener& dataLoaderStatusListener,
CreateOptions options = CreateOptions::Default);
StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage,
CreateOptions options = CreateOptions::Default);
@@ -129,13 +133,14 @@
std::string_view libDirRelativePath, std::string_view abi);
class IncrementalDataLoaderListener : public android::content::pm::BnDataLoaderStatusListener {
public:
- IncrementalDataLoaderListener(IncrementalService& incrementalService)
- : incrementalService(incrementalService) {}
+ IncrementalDataLoaderListener(IncrementalService& incrementalService, DataLoaderStatusListener externalListener)
+ : incrementalService(incrementalService), externalListener(externalListener) {}
// Callbacks interface
binder::Status onStatusChanged(MountId mount, int newStatus) override;
private:
IncrementalService& incrementalService;
+ DataLoaderStatusListener externalListener;
};
private:
@@ -201,7 +206,7 @@
std::string&& source, std::string&& target, BindKind kind,
std::unique_lock<std::mutex>& mainLock);
- bool prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel* params);
+ bool prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel* params = nullptr, const DataLoaderStatusListener* externalListener = nullptr);
BindPathMap::const_iterator findStorageLocked(std::string_view path) const;
StorageId findStorageId(std::string_view path) const;
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index f0b5672..6421583 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -60,8 +60,6 @@
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;
};
@@ -128,13 +126,6 @@
binder::Status destroyDataLoader(MountId mountId) const override {
return mInterface->destroyDataLoader(mountId);
}
- 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(MountId mountId) const override {
return mInterface->showHealthBlockedUI(mountId);
}
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 9cdc83e..f7598f7 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -293,7 +293,7 @@
EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
ASSERT_LT(storageId, 0);
}
@@ -303,7 +303,7 @@
EXPECT_CALL(*mIncrementalManager, prepareDataLoader(_, _, _, _, _)).Times(0);
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
ASSERT_LT(storageId, 0);
}
@@ -316,7 +316,7 @@
EXPECT_CALL(*mVold, unmountIncFs(_));
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
ASSERT_LT(storageId, 0);
}
@@ -330,7 +330,7 @@
EXPECT_CALL(*mVold, unmountIncFs(_));
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
ASSERT_LT(storageId, 0);
}
@@ -344,7 +344,7 @@
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
ASSERT_LT(storageId, 0);
}
@@ -358,7 +358,7 @@
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
mIncrementalService->deleteStorage(storageId);
@@ -373,7 +373,7 @@
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
mIncrementalManager->setDataLoaderStatusNotReady();
@@ -389,7 +389,7 @@
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
ASSERT_GE(storageId, 0);
mIncrementalManager->setDataLoaderStatusReady();
@@ -404,7 +404,7 @@
mIncrementalManager->startDataLoaderSuccess();
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
std::string dir_path("test");
@@ -428,7 +428,7 @@
mIncrementalManager->startDataLoaderSuccess();
TemporaryDir tempDir;
int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
IncrementalService::CreateOptions::CreateNew);
auto first = "first"sv;
auto second = "second"sv;