/* * 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 #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, "", "(Landroid/content/pm/DataLoaderParamsParcel;)V"); fileSystemConnector = (jclass)env->NewGlobalRef( FindClassOrDie(env, "android/service/dataloader/DataLoaderService$FileSystemConnector")); fileSystemConnectorConstruct = GetMethodIDOrDie(env, fileSystemConnector, "", "(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, "", "(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, "", "(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(self); me->onDestroy(); delete me; }; LegacyDataLoader::onPrepareImage = [](auto* self, const auto addedFiles[], int addedFilesCount) -> bool { return static_cast(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(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(fsConnector), static_cast(statusListener), serviceConnector, serviceParams)); }; } } // namespace android::dataloader