summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/incremental/IIncrementalService.aidl5
-rw-r--r--core/java/android/os/incremental/IncrementalStorage.java14
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java16
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java11
-rw-r--r--services/core/jni/com_android_server_SystemServer.cpp2
-rw-r--r--services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp2
-rw-r--r--services/incremental/BinderIncrementalService.cpp34
-rw-r--r--services/incremental/BinderIncrementalService.h12
-rw-r--r--services/incremental/IncrementalService.cpp247
-rw-r--r--services/incremental/IncrementalService.h34
-rw-r--r--services/incremental/ServiceWrappers.cpp180
-rw-r--r--services/incremental/ServiceWrappers.h116
-rw-r--r--services/incremental/include/incremental_service.h2
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp28
14 files changed, 482 insertions, 221 deletions
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl
index 2dbaea860e2a..25cb0400a38d 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -109,4 +109,9 @@ interface IIncrementalService {
* Setting up native library directories and extract native libs onto a storage.
*/
boolean configureNativeBinaries(int storageId, in @utf8InCpp String apkFullPath, in @utf8InCpp String libDirRelativePath, in @utf8InCpp String abi);
+
+ /**
+ * Waits until all native library extraction is done for the storage
+ */
+ boolean waitForNativeBinariesExtraction(int storageId);
}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index 7092751c0d7e..70ebbaa326b8 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -480,4 +480,18 @@ public final class IncrementalStorage {
return false;
}
}
+
+ /**
+ * Waits for all native binary extraction operations to complete on the storage.
+ *
+ * @return Success of not.
+ */
+ public boolean waitForNativeBinariesExtraction() {
+ try {
+ return mService.waitForNativeBinariesExtraction(mId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return false;
+ }
+ }
}
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 04bf91567986..02cf25a7c3d2 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -26,7 +26,6 @@ import static android.system.OsConstants.S_IXGRP;
import static android.system.OsConstants.S_IXOTH;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageLite;
@@ -40,6 +39,7 @@ import android.os.incremental.IncrementalManager;
import android.os.incremental.IncrementalStorage;
import android.system.ErrnoException;
import android.system.Os;
+import android.util.ArraySet;
import android.util.Slog;
import dalvik.system.CloseGuard;
@@ -545,4 +545,18 @@ public class NativeLibraryHelper {
}
return false;
}
+
+ /**
+ * Wait for all native library extraction to complete for the passed storages.
+ *
+ * @param incrementalStorages A list of the storages to wait for.
+ */
+ public static void waitForNativeBinariesExtraction(
+ ArraySet<IncrementalStorage> incrementalStorages) {
+ for (int i = 0; i < incrementalStorages.size(); ++i) {
+ IncrementalStorage storage = incrementalStorages.valueAtUnchecked(i);
+ storage.waitForNativeBinariesExtraction();
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9c41e6d5c6a3..59ac603875e2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -263,6 +263,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.incremental.IncrementalManager;
+import android.os.incremental.IncrementalStorage;
import android.os.storage.DiskInfo;
import android.os.storage.IStorageManager;
import android.os.storage.StorageEventListener;
@@ -16596,6 +16597,7 @@ public class PackageManagerService extends IPackageManager.Stub
* locks on {@link #mLock}.
*/
private void executePostCommitSteps(CommitRequest commitRequest) {
+ final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>();
for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) {
final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags
& PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
@@ -16603,6 +16605,14 @@ public class PackageManagerService extends IPackageManager.Stub
final String packageName = pkg.getPackageName();
final boolean onIncremental = mIncrementalManager != null
&& isIncrementalPath(pkg.getCodePath());
+ if (onIncremental) {
+ IncrementalStorage storage = mIncrementalManager.openStorage(pkg.getCodePath());
+ if (storage == null) {
+ throw new IllegalArgumentException(
+ "Install: null storage for incremental package " + packageName);
+ }
+ incrementalStorages.add(storage);
+ }
prepareAppDataAfterInstallLIF(pkg);
if (reconciledPkg.prepareResult.clearCodeCache) {
clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
@@ -16700,6 +16710,7 @@ public class PackageManagerService extends IPackageManager.Stub
notifyPackageChangeObserversOnUpdate(reconciledPkg);
}
+ NativeLibraryHelper.waitForNativeBinariesExtraction(incrementalStorages);
}
private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) {
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index e99a264c42e4..76b171337bb9 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -135,7 +135,7 @@ static void android_server_SystemServer_spawnFdLeakCheckThread(JNIEnv*, jobject)
static jlong android_server_SystemServer_startIncrementalService(JNIEnv* env, jclass klass,
jobject self) {
- return Incremental_IncrementalService_Start();
+ return Incremental_IncrementalService_Start(env);
}
static void android_server_SystemServer_setIncrementalServiceSystemReady(JNIEnv* env, jclass klass,
diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
index 853eba71d88a..e32a343433a8 100644
--- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
+++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp
@@ -410,6 +410,8 @@ private:
// Installation.
bool onPrepareImage(dataloader::DataLoaderInstallationFiles addedFiles) final {
+ ALOGE("onPrepareImage: start.");
+
JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
const auto& jni = jniIds(env);
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index aabc58c3a297..fc8c6feac22b 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -58,10 +58,10 @@ static bool incFsValid(const sp<IVold>& vold) {
return true;
}
-BinderIncrementalService::BinderIncrementalService(const sp<IServiceManager>& sm)
- : mImpl(RealServiceManager(sm), getIncrementalDir()) {}
+BinderIncrementalService::BinderIncrementalService(const sp<IServiceManager>& sm, JNIEnv* env)
+ : mImpl(RealServiceManager(sm, env), getIncrementalDir()) {}
-BinderIncrementalService* BinderIncrementalService::start() {
+BinderIncrementalService* BinderIncrementalService::start(JNIEnv* env) {
if (!incFsEnabled()) {
return nullptr;
}
@@ -81,7 +81,7 @@ BinderIncrementalService* BinderIncrementalService::start() {
return nullptr;
}
- sp<BinderIncrementalService> self(new BinderIncrementalService(sm));
+ sp<BinderIncrementalService> self(new BinderIncrementalService(sm, env));
status_t ret = sm->addService(String16{getServiceName()}, self);
if (ret != android::OK) {
return nullptr;
@@ -116,11 +116,14 @@ binder::Status BinderIncrementalService::openStorage(const std::string& path,
return ok();
}
-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), listener, android::incremental::IncrementalService::CreateOptions(createMode));
+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), listener,
+ android::incremental::IncrementalService::CreateOptions(
+ createMode));
return ok();
}
@@ -181,7 +184,8 @@ static std::tuple<int, incfs::FileId, incfs::NewFileParams> toMakeFileParams(
if (!params.signature) {
nfp.signature = {};
} else {
- nfp.signature = {(const char*)params.signature->data(), (IncFsSize)params.signature->size()};
+ nfp.signature = {(const char*)params.signature->data(),
+ (IncFsSize)params.signature->size()};
}
return {0, id, nfp};
}
@@ -278,10 +282,16 @@ binder::Status BinderIncrementalService::configureNativeBinaries(
return ok();
}
+binder::Status BinderIncrementalService::waitForNativeBinariesExtraction(int storageId,
+ bool* _aidl_return) {
+ *_aidl_return = mImpl.waitForNativeBinariesExtraction(storageId);
+ return ok();
+}
+
} // namespace android::os::incremental
-jlong Incremental_IncrementalService_Start() {
- return (jlong)android::os::incremental::BinderIncrementalService::start();
+jlong Incremental_IncrementalService_Start(JNIEnv* env) {
+ return (jlong)android::os::incremental::BinderIncrementalService::start(env);
}
void Incremental_IncrementalService_OnSystemReady(jlong self) {
if (self) {
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 28613e101b7c..5a7d5da56f18 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -18,6 +18,7 @@
#include <binder/BinderService.h>
#include <binder/IServiceManager.h>
+#include <jni.h>
#include "IncrementalService.h"
#include "android/os/incremental/BnIncrementalService.h"
@@ -28,9 +29,9 @@ namespace android::os::incremental {
class BinderIncrementalService : public BnIncrementalService,
public BinderService<BinderIncrementalService> {
public:
- BinderIncrementalService(const sp<IServiceManager>& sm);
+ BinderIncrementalService(const sp<IServiceManager>& sm, JNIEnv* env);
- static BinderIncrementalService* start();
+ static BinderIncrementalService* start(JNIEnv* env);
static const char16_t* getServiceName() { return u"incremental"; }
status_t dump(int fd, const Vector<String16>& args) final;
@@ -38,7 +39,10 @@ public:
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, const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener, 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,
@@ -68,9 +72,11 @@ public:
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 configureNativeBinaries(int32_t storageId, const std::string& apkFullPath,
const std::string& libDirRelativePath,
const std::string& abi, bool* _aidl_return) final;
+ binder::Status waitForNativeBinariesExtraction(int storageId, bool* _aidl_return) final;
private:
android::incremental::IncrementalService mImpl;
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index eb65a2ddc5f1..2c6bf0a80fe0 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -26,23 +26,18 @@
#include <android-base/strings.h>
#include <android/content/pm/IDataLoaderStatusListener.h>
#include <android/os/IVold.h>
-#include <androidfw/ZipFileRO.h>
-#include <androidfw/ZipUtils.h>
#include <binder/BinderService.h>
#include <binder/Nullable.h>
#include <binder/ParcelFileDescriptor.h>
#include <binder/Status.h>
#include <sys/stat.h>
#include <uuid/uuid.h>
-#include <zlib.h>
#include <charconv>
#include <ctime>
#include <filesystem>
#include <iterator>
#include <span>
-#include <stack>
-#include <thread>
#include <type_traits>
#include "Metadata.pb.h"
@@ -242,6 +237,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v
mDataLoaderManager(sm.getDataLoaderManager()),
mIncFs(sm.getIncFs()),
mAppOpsManager(sm.getAppOpsManager()),
+ mJni(sm.getJni()),
mIncrementalDir(rootDir) {
if (!mVold) {
LOG(FATAL) << "Vold service is unavailable";
@@ -252,6 +248,13 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v
if (!mAppOpsManager) {
LOG(FATAL) << "AppOpsManager is unavailable";
}
+
+ mJobQueue.reserve(16);
+ mJobProcessor = std::thread([this]() {
+ mJni->initializeForCurrentThread();
+ runJobProcessing();
+ });
+
mountExistingImages();
}
@@ -259,7 +262,14 @@ FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) {
return IncFs_FileIdFromMetadata({(const char*)metadata.data(), metadata.size()});
}
-IncrementalService::~IncrementalService() = default;
+IncrementalService::~IncrementalService() {
+ {
+ std::lock_guard lock(mJobMutex);
+ mRunning = false;
+ }
+ mJobCondition.notify_all();
+ mJobProcessor.join();
+}
inline const char* toString(TimePoint t) {
using SystemClock = std::chrono::system_clock;
@@ -1158,8 +1168,6 @@ static long elapsedMcs(Duration start, Duration end) {
bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
std::string_view libDirRelativePath,
std::string_view abi) {
- namespace sc = std::chrono;
- using Clock = sc::steady_clock;
auto start = Clock::now();
const auto ifs = getIfs(storage);
@@ -1176,33 +1184,35 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
}
auto mkDirsTs = Clock::now();
-
- std::unique_ptr<ZipFileRO> zipFile(ZipFileRO::open(path::c_str(apkFullPath)));
- if (!zipFile) {
+ ZipArchiveHandle zipFileHandle;
+ if (OpenArchive(path::c_str(apkFullPath), &zipFileHandle)) {
LOG(ERROR) << "Failed to open zip file at " << apkFullPath;
return false;
}
+
+ // Need a shared pointer: will be passing it into all unpacking jobs.
+ std::shared_ptr<ZipArchive> zipFile(zipFileHandle, [](ZipArchiveHandle h) { CloseArchive(h); });
void* cookie = nullptr;
const auto libFilePrefix = path::join(constants().libDir, abi);
- if (!zipFile->startIteration(&cookie, libFilePrefix.c_str() /* prefix */,
- constants().libSuffix.data() /* suffix */)) {
+ if (StartIteration(zipFile.get(), &cookie, libFilePrefix, constants().libSuffix)) {
LOG(ERROR) << "Failed to start zip iteration for " << apkFullPath;
return false;
}
- auto endIteration = [&zipFile](void* cookie) { zipFile->endIteration(cookie); };
+ auto endIteration = [](void* cookie) { EndIteration(cookie); };
auto iterationCleaner = std::unique_ptr<void, decltype(endIteration)>(cookie, endIteration);
auto openZipTs = Clock::now();
- std::vector<IncFsDataBlock> instructions;
- ZipEntryRO entry = nullptr;
- while ((entry = zipFile->nextEntry(cookie)) != nullptr) {
- auto startFileTs = Clock::now();
-
- char fileName[PATH_MAX];
- if (zipFile->getEntryFileName(entry, fileName, sizeof(fileName))) {
+ std::vector<Job> jobQueue;
+ ZipEntry entry;
+ std::string_view fileName;
+ while (!Next(cookie, &entry, &fileName)) {
+ if (fileName.empty()) {
continue;
}
+
+ auto startFileTs = Clock::now();
+
const auto libName = path::basename(fileName);
const auto targetLibPath = path::join(libDirRelativePath, libName);
const auto targetLibPathAbsolute = normalizePathToStorage(ifs, storage, targetLibPath);
@@ -1216,16 +1226,9 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
continue;
}
- uint32_t uncompressedLen, compressedLen;
- if (!zipFile->getEntryInfo(entry, nullptr, &uncompressedLen, &compressedLen, nullptr,
- nullptr, nullptr)) {
- LOG(ERROR) << "Failed to read native lib entry: " << fileName;
- return false;
- }
-
// Create new lib file without signature info
incfs::NewFileParams libFileParams = {
- .size = uncompressedLen,
+ .size = entry.uncompressed_length,
.signature = {},
// Metadata of the new lib file is its relative path
.metadata = {targetLibPath.c_str(), (IncFsSize)targetLibPath.size()},
@@ -1241,68 +1244,45 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
auto makeFileTs = Clock::now();
// If it is a zero-byte file, skip data writing
- if (uncompressedLen == 0) {
+ if (entry.uncompressed_length == 0) {
if (sEnablePerfLogging) {
- LOG(INFO) << "incfs: Extracted " << libName << "(" << compressedLen << " -> "
- << uncompressedLen << " bytes): " << elapsedMcs(startFileTs, makeFileTs)
- << "mcs, make: " << elapsedMcs(startFileTs, makeFileTs);
+ LOG(INFO) << "incfs: Extracted " << libName
+ << "(0 bytes): " << elapsedMcs(startFileTs, makeFileTs) << "mcs";
}
continue;
}
- // Write extracted data to new file
- // NOTE: don't zero-initialize memory, it may take a while
- auto libData = std::unique_ptr<uint8_t[]>(new uint8_t[uncompressedLen]);
- if (!zipFile->uncompressEntry(entry, libData.get(), uncompressedLen)) {
- LOG(ERROR) << "Failed to extract native lib zip entry: " << fileName;
- return false;
- }
-
- auto extractFileTs = Clock::now();
+ jobQueue.emplace_back([this, zipFile, entry, ifs = std::weak_ptr<IncFsMount>(ifs),
+ libFileId, libPath = std::move(targetLibPath),
+ makeFileTs]() mutable {
+ extractZipFile(ifs.lock(), zipFile.get(), entry, libFileId, libPath, makeFileTs);
+ });
- const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId);
- if (!writeFd.ok()) {
- LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd;
- return false;
+ if (sEnablePerfLogging) {
+ auto prepareJobTs = Clock::now();
+ LOG(INFO) << "incfs: Processed " << libName << ": "
+ << elapsedMcs(startFileTs, prepareJobTs)
+ << "mcs, make file: " << elapsedMcs(startFileTs, makeFileTs)
+ << " prepare job: " << elapsedMcs(makeFileTs, prepareJobTs);
}
+ }
- auto openFileTs = Clock::now();
-
- const int numBlocks = (uncompressedLen + constants().blockSize - 1) / constants().blockSize;
- instructions.clear();
- instructions.reserve(numBlocks);
- auto remainingData = std::span(libData.get(), uncompressedLen);
- for (int i = 0; i < numBlocks; i++) {
- const auto blockSize = std::min<uint16_t>(constants().blockSize, remainingData.size());
- auto inst = IncFsDataBlock{
- .fileFd = writeFd.get(),
- .pageIndex = static_cast<IncFsBlockIndex>(i),
- .compression = INCFS_COMPRESSION_KIND_NONE,
- .kind = INCFS_BLOCK_KIND_DATA,
- .dataSize = blockSize,
- .data = reinterpret_cast<const char*>(remainingData.data()),
- };
- instructions.push_back(inst);
- remainingData = remainingData.subspan(blockSize);
- }
- auto prepareInstsTs = Clock::now();
+ auto processedTs = Clock::now();
- size_t res = mIncFs->writeBlocks(instructions);
- if (res != instructions.size()) {
- LOG(ERROR) << "Failed to write data into: " << targetLibPath;
- return false;
- }
-
- if (sEnablePerfLogging) {
- auto endFileTs = Clock::now();
- LOG(INFO) << "incfs: Extracted " << libName << "(" << compressedLen << " -> "
- << uncompressedLen << " bytes): " << elapsedMcs(startFileTs, endFileTs)
- << "mcs, make: " << elapsedMcs(startFileTs, makeFileTs)
- << " extract: " << elapsedMcs(makeFileTs, extractFileTs)
- << " open: " << elapsedMcs(extractFileTs, openFileTs)
- << " prepare: " << elapsedMcs(openFileTs, prepareInstsTs)
- << " write:" << elapsedMcs(prepareInstsTs, endFileTs);
+ if (!jobQueue.empty()) {
+ {
+ std::lock_guard lock(mJobMutex);
+ if (mRunning) {
+ auto& existingJobs = mJobQueue[storage];
+ if (existingJobs.empty()) {
+ existingJobs = std::move(jobQueue);
+ } else {
+ existingJobs.insert(existingJobs.end(), std::move_iterator(jobQueue.begin()),
+ std::move_iterator(jobQueue.end()));
+ }
+ }
}
+ mJobCondition.notify_all();
}
if (sEnablePerfLogging) {
@@ -1310,12 +1290,112 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
LOG(INFO) << "incfs: configureNativeBinaries complete in " << elapsedMcs(start, end)
<< "mcs, make dirs: " << elapsedMcs(start, mkDirsTs)
<< " open zip: " << elapsedMcs(mkDirsTs, openZipTs)
- << " extract all: " << elapsedMcs(openZipTs, end);
+ << " make files: " << elapsedMcs(openZipTs, processedTs)
+ << " schedule jobs: " << elapsedMcs(processedTs, end);
}
return true;
}
+void IncrementalService::extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile,
+ ZipEntry& entry, const incfs::FileId& libFileId,
+ std::string_view targetLibPath,
+ Clock::time_point scheduledTs) {
+ if (!ifs) {
+ LOG(INFO) << "Skipping zip file " << targetLibPath << " extraction for an expired mount";
+ return;
+ }
+
+ auto libName = path::basename(targetLibPath);
+ auto startedTs = Clock::now();
+
+ // Write extracted data to new file
+ // NOTE: don't zero-initialize memory, it may take a while for nothing
+ auto libData = std::unique_ptr<uint8_t[]>(new uint8_t[entry.uncompressed_length]);
+ if (ExtractToMemory(zipFile, &entry, libData.get(), entry.uncompressed_length)) {
+ LOG(ERROR) << "Failed to extract native lib zip entry: " << libName;
+ return;
+ }
+
+ auto extractFileTs = Clock::now();
+
+ const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId);
+ if (!writeFd.ok()) {
+ LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd;
+ return;
+ }
+
+ auto openFileTs = Clock::now();
+ const int numBlocks =
+ (entry.uncompressed_length + constants().blockSize - 1) / constants().blockSize;
+ std::vector<IncFsDataBlock> instructions(numBlocks);
+ auto remainingData = std::span(libData.get(), entry.uncompressed_length);
+ for (int i = 0; i < numBlocks; i++) {
+ const auto blockSize = std::min<uint16_t>(constants().blockSize, remainingData.size());
+ instructions[i] = IncFsDataBlock{
+ .fileFd = writeFd.get(),
+ .pageIndex = static_cast<IncFsBlockIndex>(i),
+ .compression = INCFS_COMPRESSION_KIND_NONE,
+ .kind = INCFS_BLOCK_KIND_DATA,
+ .dataSize = blockSize,
+ .data = reinterpret_cast<const char*>(remainingData.data()),
+ };
+ remainingData = remainingData.subspan(blockSize);
+ }
+ auto prepareInstsTs = Clock::now();
+
+ size_t res = mIncFs->writeBlocks(instructions);
+ if (res != instructions.size()) {
+ LOG(ERROR) << "Failed to write data into: " << targetLibPath;
+ return;
+ }
+
+ if (sEnablePerfLogging) {
+ auto endFileTs = Clock::now();
+ LOG(INFO) << "incfs: Extracted " << libName << "(" << entry.compressed_length << " -> "
+ << entry.uncompressed_length << " bytes): " << elapsedMcs(startedTs, endFileTs)
+ << "mcs, scheduling delay: " << elapsedMcs(scheduledTs, startedTs)
+ << " extract: " << elapsedMcs(startedTs, extractFileTs)
+ << " open: " << elapsedMcs(extractFileTs, openFileTs)
+ << " prepare: " << elapsedMcs(openFileTs, prepareInstsTs)
+ << " write: " << elapsedMcs(prepareInstsTs, endFileTs);
+ }
+}
+
+bool IncrementalService::waitForNativeBinariesExtraction(StorageId storage) {
+ std::unique_lock lock(mJobMutex);
+ mJobCondition.wait(lock, [this, storage] {
+ return !mRunning ||
+ (mPendingJobsStorage != storage && mJobQueue.find(storage) == mJobQueue.end());
+ });
+ return mPendingJobsStorage != storage && mJobQueue.find(storage) == mJobQueue.end();
+}
+
+void IncrementalService::runJobProcessing() {
+ for (;;) {
+ std::unique_lock lock(mJobMutex);
+ mJobCondition.wait(lock, [this]() { return !mRunning || !mJobQueue.empty(); });
+ if (!mRunning) {
+ return;
+ }
+
+ auto it = mJobQueue.begin();
+ mPendingJobsStorage = it->first;
+ auto queue = std::move(it->second);
+ mJobQueue.erase(it);
+ lock.unlock();
+
+ for (auto&& job : queue) {
+ job();
+ }
+
+ lock.lock();
+ mPendingJobsStorage = kInvalidStorageId;
+ lock.unlock();
+ mJobCondition.notify_all();
+ }
+}
+
void IncrementalService::registerAppOpsCallback(const std::string& packageName) {
sp<IAppOpsCallback> listener;
{
@@ -1328,7 +1408,8 @@ void IncrementalService::registerAppOpsCallback(const std::string& packageName)
listener = cb;
}
- mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, String16(packageName.c_str()), listener);
+ mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS,
+ String16(packageName.c_str()), listener);
}
bool IncrementalService::unregisterAppOpsCallback(const std::string& packageName) {
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 27d40f1506ca..e7705df633d1 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -23,16 +23,19 @@
#include <utils/String16.h>
#include <utils/StrongPointer.h>
#include <utils/Vector.h>
+#include <ziparchive/zip_archive.h>
#include <atomic>
#include <chrono>
-#include <future>
+#include <condition_variable>
+#include <functional>
#include <limits>
#include <map>
#include <mutex>
#include <span>
#include <string>
#include <string_view>
+#include <thread>
#include <unordered_map>
#include <utility>
#include <vector>
@@ -132,12 +135,15 @@ public:
std::vector<std::string> listFiles(StorageId storage) const;
bool startLoading(StorageId storage) const;
+
bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
std::string_view libDirRelativePath, std::string_view abi);
+ bool waitForNativeBinariesExtraction(StorageId storage);
class AppOpsListener : public android::BnAppOpsCallback {
public:
- AppOpsListener(IncrementalService& incrementalService, std::string packageName) : incrementalService(incrementalService), packageName(std::move(packageName)) {}
+ AppOpsListener(IncrementalService& incrementalService, std::string packageName)
+ : incrementalService(incrementalService), packageName(std::move(packageName)) {}
void opChanged(int32_t op, const String16& packageName) final;
private:
@@ -277,11 +283,17 @@ private:
bool unregisterAppOpsCallback(const std::string& packageName);
void onAppOpChanged(const std::string& packageName);
- // Member variables
- std::unique_ptr<VoldServiceWrapper> const mVold;
- std::unique_ptr<DataLoaderManagerWrapper> const mDataLoaderManager;
- std::unique_ptr<IncFsWrapper> const mIncFs;
- std::unique_ptr<AppOpsManagerWrapper> const mAppOpsManager;
+ void runJobProcessing();
+ void extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile, ZipEntry& entry,
+ const incfs::FileId& libFileId, std::string_view targetLibPath,
+ Clock::time_point scheduledTs);
+
+private:
+ const std::unique_ptr<VoldServiceWrapper> mVold;
+ const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager;
+ const std::unique_ptr<IncFsWrapper> mIncFs;
+ const std::unique_ptr<AppOpsManagerWrapper> mAppOpsManager;
+ const std::unique_ptr<JniWrapper> mJni;
const std::string mIncrementalDir;
mutable std::mutex mLock;
@@ -294,6 +306,14 @@ private:
std::atomic_bool mSystemReady = false;
StorageId mNextId = 0;
+
+ using Job = std::function<void()>;
+ std::unordered_map<StorageId, std::vector<Job>> mJobQueue;
+ StorageId mPendingJobsStorage = kInvalidStorageId;
+ std::condition_variable mJobCondition;
+ std::mutex mJobMutex;
+ std::thread mJobProcessor;
+ bool mRunning = true;
};
} // namespace android::incremental
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 9f4192fbf531..bf8e696a264c 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -14,8 +14,11 @@
* limitations under the License.
*/
+#define LOG_TAG "IncrementalService"
+
#include "ServiceWrappers.h"
+#include <android-base/logging.h>
#include <utils/String16.h>
using namespace std::literals;
@@ -25,8 +28,123 @@ namespace android::os::incremental {
static constexpr auto kVoldServiceName = "vold"sv;
static constexpr auto kDataLoaderManagerName = "dataloader_manager"sv;
-RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager)
- : mServiceManager(std::move(serviceManager)) {}
+class RealVoldService : public VoldServiceWrapper {
+public:
+ RealVoldService(const sp<os::IVold> vold) : mInterface(std::move(vold)) {}
+ ~RealVoldService() = default;
+ binder::Status mountIncFs(const std::string& backingPath, const std::string& targetDir,
+ int32_t flags,
+ IncrementalFileSystemControlParcel* _aidl_return) const final {
+ return mInterface->mountIncFs(backingPath, targetDir, flags, _aidl_return);
+ }
+ binder::Status unmountIncFs(const std::string& dir) const final {
+ return mInterface->unmountIncFs(dir);
+ }
+ binder::Status bindMount(const std::string& sourceDir,
+ const std::string& targetDir) const final {
+ return mInterface->bindMount(sourceDir, targetDir);
+ }
+ binder::Status setIncFsMountOptions(
+ const ::android::os::incremental::IncrementalFileSystemControlParcel& control,
+ bool enableReadLogs) const final {
+ return mInterface->setIncFsMountOptions(control, enableReadLogs);
+ }
+
+private:
+ sp<os::IVold> mInterface;
+};
+
+class RealDataLoaderManager : public DataLoaderManagerWrapper {
+public:
+ RealDataLoaderManager(const sp<content::pm::IDataLoaderManager> manager)
+ : mInterface(manager) {}
+ ~RealDataLoaderManager() = default;
+ binder::Status initializeDataLoader(MountId mountId, const DataLoaderParamsParcel& params,
+ const FileSystemControlParcel& control,
+ const sp<IDataLoaderStatusListener>& listener,
+ bool* _aidl_return) const final {
+ return mInterface->initializeDataLoader(mountId, params, control, listener, _aidl_return);
+ }
+ binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const final {
+ return mInterface->getDataLoader(mountId, _aidl_return);
+ }
+ binder::Status destroyDataLoader(MountId mountId) const final {
+ return mInterface->destroyDataLoader(mountId);
+ }
+
+private:
+ sp<content::pm::IDataLoaderManager> mInterface;
+};
+
+class RealAppOpsManager : public AppOpsManagerWrapper {
+public:
+ ~RealAppOpsManager() = default;
+ binder::Status checkPermission(const char* permission, const char* operation,
+ const char* package) const final {
+ return android::incremental::CheckPermissionForDataDelivery(permission, operation, package);
+ }
+ void startWatchingMode(int32_t op, const String16& packageName,
+ const sp<IAppOpsCallback>& callback) final {
+ mAppOpsManager.startWatchingMode(op, packageName, callback);
+ }
+ void stopWatchingMode(const sp<IAppOpsCallback>& callback) final {
+ mAppOpsManager.stopWatchingMode(callback);
+ }
+
+private:
+ android::AppOpsManager mAppOpsManager;
+};
+
+class RealJniWrapper final : public JniWrapper {
+public:
+ RealJniWrapper(JavaVM* jvm);
+ void initializeForCurrentThread() const final;
+
+ static JavaVM* getJvm(JNIEnv* env);
+
+private:
+ JavaVM* const mJvm;
+};
+
+class RealIncFs : public IncFsWrapper {
+public:
+ RealIncFs() = default;
+ ~RealIncFs() = default;
+ Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) const final {
+ return incfs::createControl(cmd, pendingReads, logs);
+ }
+ ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId id,
+ NewFileParams params) const final {
+ return incfs::makeFile(control, path, mode, id, params);
+ }
+ ErrorCode makeDir(const Control& control, std::string_view path, int mode) const final {
+ return incfs::makeDir(control, path, mode);
+ }
+ RawMetadata getMetadata(const Control& control, FileId fileid) const final {
+ return incfs::getMetadata(control, fileid);
+ }
+ RawMetadata getMetadata(const Control& control, std::string_view path) const final {
+ return incfs::getMetadata(control, path);
+ }
+ FileId getFileId(const Control& control, std::string_view path) const final {
+ return incfs::getFileId(control, path);
+ }
+ ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final {
+ return incfs::link(control, from, to);
+ }
+ ErrorCode unlink(const Control& control, std::string_view path) const final {
+ return incfs::unlink(control, path);
+ }
+ base::unique_fd openForSpecialOps(const Control& control, FileId id) const final {
+ return base::unique_fd{incfs::openForSpecialOps(control, id).release()};
+ }
+ ErrorCode writeBlocks(Span<const DataBlock> blocks) const final {
+ return incfs::writeBlocks(blocks);
+ }
+};
+
+RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env)
+ : mServiceManager(std::move(serviceManager)), mJvm(RealJniWrapper::getJvm(env)) {}
template <class INTERFACE>
sp<INTERFACE> RealServiceManager::getRealService(std::string_view serviceName) const {
@@ -63,4 +181,62 @@ std::unique_ptr<AppOpsManagerWrapper> RealServiceManager::getAppOpsManager() {
return std::make_unique<RealAppOpsManager>();
}
+std::unique_ptr<JniWrapper> RealServiceManager::getJni() {
+ return std::make_unique<RealJniWrapper>(mJvm);
+}
+
+static JavaVM* getJavaVm(JNIEnv* env) {
+ CHECK(env);
+ JavaVM* jvm = nullptr;
+ env->GetJavaVM(&jvm);
+ CHECK(jvm);
+ return jvm;
+}
+
+static JNIEnv* getJniEnv(JavaVM* vm) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ return nullptr;
+ }
+ return env;
+}
+
+static JNIEnv* getOrAttachJniEnv(JavaVM* jvm) {
+ if (!jvm) {
+ LOG(ERROR) << "No JVM instance";
+ return nullptr;
+ }
+
+ JNIEnv* env = getJniEnv(jvm);
+ if (!env) {
+ int result = jvm->AttachCurrentThread(&env, nullptr);
+ if (result != JNI_OK) {
+ LOG(ERROR) << "JVM thread attach failed: " << result;
+ return nullptr;
+ }
+ struct VmDetacher {
+ VmDetacher(JavaVM* vm) : mVm(vm) {}
+ ~VmDetacher() { mVm->DetachCurrentThread(); }
+
+ private:
+ JavaVM* const mVm;
+ };
+ static thread_local VmDetacher detacher(jvm);
+ }
+
+ return env;
+}
+
+RealJniWrapper::RealJniWrapper(JavaVM* jvm) : mJvm(jvm) {
+ CHECK(!!mJvm) << "JVM is unavailable";
+}
+
+void RealJniWrapper::initializeForCurrentThread() const {
+ (void)getOrAttachJniEnv(mJvm);
+}
+
+JavaVM* RealJniWrapper::getJvm(JNIEnv* env) {
+ return getJavaVm(env);
+}
+
} // namespace android::os::incremental
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 84bf1ffaf45c..142bf2ef32f3 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -29,6 +29,7 @@
#include <binder/AppOpsManager.h>
#include <binder/IServiceManager.h>
#include <incfs.h>
+#include <jni.h>
#include <memory>
#include <string>
@@ -93,6 +94,12 @@ public:
virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
};
+class JniWrapper {
+public:
+ virtual ~JniWrapper() = default;
+ virtual void initializeForCurrentThread() const = 0;
+};
+
class ServiceManagerWrapper {
public:
virtual ~ServiceManagerWrapper() = default;
@@ -100,127 +107,26 @@ public:
virtual std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() = 0;
virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0;
virtual std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() = 0;
+ virtual std::unique_ptr<JniWrapper> getJni() = 0;
};
// --- Real stuff ---
-class RealVoldService : public VoldServiceWrapper {
-public:
- RealVoldService(const sp<os::IVold> vold) : mInterface(std::move(vold)) {}
- ~RealVoldService() = default;
- binder::Status mountIncFs(const std::string& backingPath, const std::string& targetDir,
- int32_t flags,
- IncrementalFileSystemControlParcel* _aidl_return) const final {
- return mInterface->mountIncFs(backingPath, targetDir, flags, _aidl_return);
- }
- binder::Status unmountIncFs(const std::string& dir) const final {
- return mInterface->unmountIncFs(dir);
- }
- binder::Status bindMount(const std::string& sourceDir,
- const std::string& targetDir) const final {
- return mInterface->bindMount(sourceDir, targetDir);
- }
- binder::Status setIncFsMountOptions(
- const ::android::os::incremental::IncrementalFileSystemControlParcel& control,
- bool enableReadLogs) const final {
- return mInterface->setIncFsMountOptions(control, enableReadLogs);
- }
-
-private:
- sp<os::IVold> mInterface;
-};
-
-class RealDataLoaderManager : public DataLoaderManagerWrapper {
-public:
- RealDataLoaderManager(const sp<content::pm::IDataLoaderManager> manager)
- : mInterface(manager) {}
- ~RealDataLoaderManager() = default;
- binder::Status initializeDataLoader(MountId mountId, const DataLoaderParamsParcel& params,
- const FileSystemControlParcel& control,
- const sp<IDataLoaderStatusListener>& listener,
- bool* _aidl_return) const final {
- return mInterface->initializeDataLoader(mountId, params, control, listener, _aidl_return);
- }
- binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const final {
- return mInterface->getDataLoader(mountId, _aidl_return);
- }
- binder::Status destroyDataLoader(MountId mountId) const final {
- return mInterface->destroyDataLoader(mountId);
- }
-
-private:
- sp<content::pm::IDataLoaderManager> mInterface;
-};
-
-class RealAppOpsManager : public AppOpsManagerWrapper {
-public:
- ~RealAppOpsManager() = default;
- binder::Status checkPermission(const char* permission, const char* operation,
- const char* package) const final {
- return android::incremental::CheckPermissionForDataDelivery(permission, operation, package);
- }
- void startWatchingMode(int32_t op, const String16& packageName,
- const sp<IAppOpsCallback>& callback) final {
- mAppOpsManager.startWatchingMode(op, packageName, callback);
- }
- void stopWatchingMode(const sp<IAppOpsCallback>& callback) final {
- mAppOpsManager.stopWatchingMode(callback);
- }
-
-private:
- android::AppOpsManager mAppOpsManager;
-};
-
class RealServiceManager : public ServiceManagerWrapper {
public:
- RealServiceManager(sp<IServiceManager> serviceManager);
+ RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env);
~RealServiceManager() = default;
std::unique_ptr<VoldServiceWrapper> getVoldService() final;
std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final;
std::unique_ptr<IncFsWrapper> getIncFs() final;
std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final;
+ std::unique_ptr<JniWrapper> getJni() final;
private:
template <class INTERFACE>
sp<INTERFACE> getRealService(std::string_view serviceName) const;
sp<android::IServiceManager> mServiceManager;
-};
-
-class RealIncFs : public IncFsWrapper {
-public:
- RealIncFs() = default;
- ~RealIncFs() = default;
- Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) const final {
- return incfs::createControl(cmd, pendingReads, logs);
- }
- ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId id,
- NewFileParams params) const final {
- return incfs::makeFile(control, path, mode, id, params);
- }
- ErrorCode makeDir(const Control& control, std::string_view path, int mode) const final {
- return incfs::makeDir(control, path, mode);
- }
- RawMetadata getMetadata(const Control& control, FileId fileid) const final {
- return incfs::getMetadata(control, fileid);
- }
- RawMetadata getMetadata(const Control& control, std::string_view path) const final {
- return incfs::getMetadata(control, path);
- }
- FileId getFileId(const Control& control, std::string_view path) const final {
- return incfs::getFileId(control, path);
- }
- ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final {
- return incfs::link(control, from, to);
- }
- ErrorCode unlink(const Control& control, std::string_view path) const final {
- return incfs::unlink(control, path);
- }
- base::unique_fd openForSpecialOps(const Control& control, FileId id) const final {
- return base::unique_fd{incfs::openForSpecialOps(control, id).release()};
- }
- ErrorCode writeBlocks(Span<const DataBlock> blocks) const final {
- return incfs::writeBlocks(blocks);
- }
+ JavaVM* const mJvm;
};
} // namespace android::os::incremental
diff --git a/services/incremental/include/incremental_service.h b/services/incremental/include/incremental_service.h
index 4a34b11261b9..321387531694 100644
--- a/services/incremental/include/incremental_service.h
+++ b/services/incremental/include/incremental_service.h
@@ -24,7 +24,7 @@ __BEGIN_DECLS
#define INCREMENTAL_LIBRARY_NAME "service.incremental.so"
-jlong Incremental_IncrementalService_Start();
+jlong Incremental_IncrementalService_Start(JNIEnv* env);
void Incremental_IncrementalService_OnSystemReady(jlong self);
void Incremental_IncrementalService_OnDump(jlong self, jint fd);
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 991131950531..117dca8c37b3 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -261,28 +261,39 @@ public:
sp<IAppOpsCallback> mStoredCallback;
};
+class MockJniWrapper : public JniWrapper {
+public:
+ MOCK_CONST_METHOD0(initializeForCurrentThread, void());
+
+ MockJniWrapper() { EXPECT_CALL(*this, initializeForCurrentThread()).Times(1); }
+};
+
class MockServiceManager : public ServiceManagerWrapper {
public:
MockServiceManager(std::unique_ptr<MockVoldService> vold,
- std::unique_ptr<MockDataLoaderManager> manager,
+ std::unique_ptr<MockDataLoaderManager> dataLoaderManager,
std::unique_ptr<MockIncFs> incfs,
- std::unique_ptr<MockAppOpsManager> appOpsManager)
+ std::unique_ptr<MockAppOpsManager> appOpsManager,
+ std::unique_ptr<MockJniWrapper> jni)
: mVold(std::move(vold)),
- mDataLoaderManager(std::move(manager)),
+ mDataLoaderManager(std::move(dataLoaderManager)),
mIncFs(std::move(incfs)),
- mAppOpsManager(std::move(appOpsManager)) {}
+ mAppOpsManager(std::move(appOpsManager)),
+ mJni(std::move(jni)) {}
std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); }
std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final {
return std::move(mDataLoaderManager);
}
std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); }
std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); }
+ std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); }
private:
std::unique_ptr<MockVoldService> mVold;
std::unique_ptr<MockDataLoaderManager> mDataLoaderManager;
std::unique_ptr<MockIncFs> mIncFs;
std::unique_ptr<MockAppOpsManager> mAppOpsManager;
+ std::unique_ptr<MockJniWrapper> mJni;
};
// --- IncrementalServiceTest ---
@@ -298,11 +309,15 @@ public:
mIncFs = incFs.get();
auto appOps = std::make_unique<NiceMock<MockAppOpsManager>>();
mAppOpsManager = appOps.get();
+ auto jni = std::make_unique<NiceMock<MockJniWrapper>>();
+ mJni = jni.get();
mIncrementalService =
std::make_unique<IncrementalService>(MockServiceManager(std::move(vold),
- std::move(dataloaderManager),
+ std::move(
+ dataloaderManager),
std::move(incFs),
- std::move(appOps)),
+ std::move(appOps),
+ std::move(jni)),
mRootDir.path);
mDataLoaderParcel.packageName = "com.test";
mDataLoaderParcel.arguments = "uri";
@@ -336,6 +351,7 @@ protected:
NiceMock<MockIncFs>* mIncFs;
NiceMock<MockDataLoaderManager>* mDataLoaderManager;
NiceMock<MockAppOpsManager>* mAppOpsManager;
+ NiceMock<MockJniWrapper>* mJni;
std::unique_ptr<IncrementalService> mIncrementalService;
TemporaryDir mRootDir;
DataLoaderParamsParcel mDataLoaderParcel;