blob: c277d45bf0167ad201279e59a5690f2a41b66957 [file] [log] [blame]
/*
* Copyright (C) 2019 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 LOG_TAG "dataloader-manageddataloader"
#include "ManagedDataLoader.h"
#include <android-base/logging.h>
#include "JNIHelpers.h"
namespace android::dataloader {
namespace {
struct JniIds {
jclass dataLoaderParams;
jmethodID dataLoaderParamsConstruct;
jclass fileSystemConnector;
jmethodID fileSystemConnectorConstruct;
jmethodID dataLoaderServiceOnCreateDataLoader;
jmethodID dataLoaderOnCreate;
jmethodID dataLoaderOnPrepareImage;
jclass installationFile;
jmethodID installationFileCtor;
jclass arrayList;
jmethodID arrayListCtor;
jmethodID arrayListAdd;
JniIds(JNIEnv* env) {
dataLoaderParams = (jclass)env->NewGlobalRef(
FindClassOrDie(env, "android/content/pm/DataLoaderParams"));
dataLoaderParamsConstruct =
GetMethodIDOrDie(env, dataLoaderParams, "<init>",
"(Landroid/content/pm/DataLoaderParamsParcel;)V");
fileSystemConnector = (jclass)env->NewGlobalRef(
FindClassOrDie(env,
"android/service/dataloader/DataLoaderService$FileSystemConnector"));
fileSystemConnectorConstruct = GetMethodIDOrDie(env, fileSystemConnector, "<init>", "(J)V");
auto dataLoaderService =
FindClassOrDie(env, "android/service/dataloader/DataLoaderService");
dataLoaderServiceOnCreateDataLoader =
GetMethodIDOrDie(env, dataLoaderService, "onCreateDataLoader",
"(Landroid/content/pm/DataLoaderParams;)Landroid/service/"
"dataloader/DataLoaderService$DataLoader;");
auto dataLoader =
FindClassOrDie(env, "android/service/dataloader/DataLoaderService$DataLoader");
dataLoaderOnCreate =
GetMethodIDOrDie(env, dataLoader, "onCreate",
"(Landroid/content/pm/DataLoaderParams;Landroid/service/"
"dataloader/DataLoaderService$FileSystemConnector;)Z");
dataLoaderOnPrepareImage =
GetMethodIDOrDie(env, dataLoader, "onPrepareImage",
"(Ljava/util/Collection;Ljava/util/Collection;)Z");
arrayList = (jclass)env->NewGlobalRef(FindClassOrDie(env, "java/util/ArrayList"));
arrayListCtor = GetMethodIDOrDie(env, arrayList, "<init>", "(I)V");
arrayListAdd = GetMethodIDOrDie(env, arrayList, "add", "(Ljava/lang/Object;)Z");
installationFile = (jclass)env->NewGlobalRef(
FindClassOrDie(env, "android/content/pm/InstallationFile"));
installationFileCtor =
GetMethodIDOrDie(env, installationFile, "<init>", "(ILjava/lang/String;J[B[B)V");
}
};
const JniIds& jniIds(JNIEnv* env) {
static const JniIds ids(env);
return ids;
}
} // namespace
ManagedDataLoader::ManagedDataLoader(JavaVM* jvm, jobject dataLoader)
: mJvm(jvm), mDataLoader(dataLoader) {
CHECK(mJvm);
LegacyDataLoader::onStart = [](auto) -> bool { return true; };
LegacyDataLoader::onStop = [](auto) {};
LegacyDataLoader::onDestroy = [](LegacyDataLoader* self) {
auto me = static_cast<ManagedDataLoader*>(self);
me->onDestroy();
delete me;
};
LegacyDataLoader::onPrepareImage = [](auto* self, const auto addedFiles[],
int addedFilesCount) -> bool {
return static_cast<ManagedDataLoader*>(self)->onPrepareImage(
DataLoaderInstallationFiles(addedFiles, addedFilesCount));
};
LegacyDataLoader::onPendingReads = [](auto, auto, auto) {};
LegacyDataLoader::onPageReads = [](auto, auto, auto) {};
}
LegacyDataLoader* ManagedDataLoader::create(JavaVM* jvm,
android::dataloader::FilesystemConnectorPtr ifs,
android::dataloader::StatusListenerPtr listener,
android::dataloader::ServiceConnectorPtr service,
android::dataloader::ServiceParamsPtr params) {
JNIEnv* env = GetJNIEnvironment(jvm);
const auto& jni = jniIds(env);
jobject dlp = env->NewObject(jni.dataLoaderParams, jni.dataLoaderParamsConstruct, params);
jobject ifsc =
env->NewObject(jni.fileSystemConnector, jni.fileSystemConnectorConstruct, (jlong)ifs);
auto dataLoader = env->CallObjectMethod(service, jni.dataLoaderServiceOnCreateDataLoader, dlp);
if (!dataLoader) {
LOG(ERROR) << "Failed to create Java DataLoader.";
return nullptr;
}
if (env->ExceptionCheck()) {
return nullptr;
}
if (!env->CallBooleanMethod(dataLoader, jni.dataLoaderOnCreate, dlp, ifsc)) {
return nullptr;
}
return new ManagedDataLoader(jvm, env->NewGlobalRef(dataLoader));
}
void ManagedDataLoader::onDestroy() {
CHECK(mDataLoader);
JNIEnv* env = GetJNIEnvironment(mJvm);
env->DeleteGlobalRef(mDataLoader);
mDataLoader = nullptr;
}
static jobject toJavaArrayList(JNIEnv* env, const JniIds& jni,
const DataLoaderInstallationFiles& files) {
jobject arrayList =
env->NewObject(jni.arrayList, jni.arrayListCtor, static_cast<jint>(files.size()));
for (const auto& file : files) {
const auto location(file.location);
const auto size(file.size);
jstring name = env->NewStringUTF(file.name);
jbyteArray metadata = env->NewByteArray(file.metadata.size);
if (metadata != nullptr) {
env->SetByteArrayRegion(metadata, 0, file.metadata.size,
(const jbyte*)file.metadata.data);
}
jobject jfile = env->NewObject(jni.installationFile, jni.installationFileCtor, location,
name, size, metadata, nullptr);
env->CallBooleanMethod(arrayList, jni.arrayListAdd, jfile);
}
return arrayList;
}
bool ManagedDataLoader::onPrepareImage(DataLoaderInstallationFiles addedFiles) {
CHECK(mDataLoader);
auto env = GetOrAttachJNIEnvironment(mJvm);
const auto& jni = jniIds(env);
jobject jaddedFiles = toJavaArrayList(env, jni, addedFiles);
return env->CallBooleanMethod(mDataLoader, jni.dataLoaderOnPrepareImage, jaddedFiles, nullptr);
}
ManagedDataLoaderFactory::ManagedDataLoaderFactory() {
::DataLoaderFactory::onCreate =
[](::DataLoaderFactory* self, const ::DataLoaderParams* ndkParams,
::DataLoaderFilesystemConnectorPtr fsConnector,
::DataLoaderStatusListenerPtr statusListener, ::DataLoaderServiceVmPtr vm,
::DataLoaderServiceConnectorPtr serviceConnector,
::DataLoaderServiceParamsPtr serviceParams) -> ::DataLoader* {
return reinterpret_cast<::DataLoader*>(
ManagedDataLoader::create(vm, static_cast<FilesystemConnector*>(fsConnector),
static_cast<StatusListener*>(statusListener),
serviceConnector, serviceParams));
};
}
} // namespace android::dataloader