1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #define LOG_TAG "dataloader-manageddataloader"
17
18 #include "ManagedDataLoader.h"
19
20 #include <android-base/logging.h>
21
22 #include "JNIHelpers.h"
23
24 namespace android::dataloader {
25
26 namespace {
27
28 struct JniIds {
29 jclass dataLoaderParams;
30 jmethodID dataLoaderParamsConstruct;
31
32 jclass fileSystemConnector;
33 jmethodID fileSystemConnectorConstruct;
34
35 jmethodID dataLoaderServiceOnCreateDataLoader;
36
37 jmethodID dataLoaderOnCreate;
38 jmethodID dataLoaderOnPrepareImage;
39
40 jclass installationFile;
41 jmethodID installationFileCtor;
42
43 jclass arrayList;
44 jmethodID arrayListCtor;
45 jmethodID arrayListAdd;
46
JniIdsandroid::dataloader::__anon3d084ec20111::JniIds47 JniIds(JNIEnv* env) {
48 dataLoaderParams = (jclass)env->NewGlobalRef(
49 FindClassOrDie(env, "android/content/pm/DataLoaderParams"));
50 dataLoaderParamsConstruct =
51 GetMethodIDOrDie(env, dataLoaderParams, "<init>",
52 "(Landroid/content/pm/DataLoaderParamsParcel;)V");
53
54 fileSystemConnector = (jclass)env->NewGlobalRef(
55 FindClassOrDie(env,
56 "android/service/dataloader/DataLoaderService$FileSystemConnector"));
57 fileSystemConnectorConstruct = GetMethodIDOrDie(env, fileSystemConnector, "<init>", "(J)V");
58
59 auto dataLoaderService =
60 FindClassOrDie(env, "android/service/dataloader/DataLoaderService");
61 dataLoaderServiceOnCreateDataLoader =
62 GetMethodIDOrDie(env, dataLoaderService, "onCreateDataLoader",
63 "(Landroid/content/pm/DataLoaderParams;)Landroid/service/"
64 "dataloader/DataLoaderService$DataLoader;");
65
66 auto dataLoader =
67 FindClassOrDie(env, "android/service/dataloader/DataLoaderService$DataLoader");
68 dataLoaderOnCreate =
69 GetMethodIDOrDie(env, dataLoader, "onCreate",
70 "(Landroid/content/pm/DataLoaderParams;Landroid/service/"
71 "dataloader/DataLoaderService$FileSystemConnector;)Z");
72 dataLoaderOnPrepareImage =
73 GetMethodIDOrDie(env, dataLoader, "onPrepareImage",
74 "(Ljava/util/Collection;Ljava/util/Collection;)Z");
75
76 arrayList = (jclass)env->NewGlobalRef(FindClassOrDie(env, "java/util/ArrayList"));
77 arrayListCtor = GetMethodIDOrDie(env, arrayList, "<init>", "(I)V");
78 arrayListAdd = GetMethodIDOrDie(env, arrayList, "add", "(Ljava/lang/Object;)Z");
79
80 installationFile = (jclass)env->NewGlobalRef(
81 FindClassOrDie(env, "android/content/pm/InstallationFile"));
82 installationFileCtor =
83 GetMethodIDOrDie(env, installationFile, "<init>", "(ILjava/lang/String;J[B[B)V");
84 }
85 };
86
jniIds(JNIEnv * env)87 const JniIds& jniIds(JNIEnv* env) {
88 static const JniIds ids(env);
89 return ids;
90 }
91
92 } // namespace
93
ManagedDataLoader(JavaVM * jvm,jobject dataLoader)94 ManagedDataLoader::ManagedDataLoader(JavaVM* jvm, jobject dataLoader)
95 : mJvm(jvm), mDataLoader(dataLoader) {
96 CHECK(mJvm);
97
98 LegacyDataLoader::onStart = [](auto) -> bool { return true; };
99 LegacyDataLoader::onStop = [](auto) {};
100 LegacyDataLoader::onDestroy = [](LegacyDataLoader* self) {
101 auto me = static_cast<ManagedDataLoader*>(self);
102 me->onDestroy();
103 delete me;
104 };
105 LegacyDataLoader::onPrepareImage = [](auto* self, const auto addedFiles[],
106 int addedFilesCount) -> bool {
107 return static_cast<ManagedDataLoader*>(self)->onPrepareImage(
108 DataLoaderInstallationFiles(addedFiles, addedFilesCount));
109 };
110 LegacyDataLoader::onPendingReads = [](auto, auto, auto) {};
111 LegacyDataLoader::onPageReads = [](auto, auto, auto) {};
112 }
113
create(JavaVM * jvm,android::dataloader::FilesystemConnectorPtr ifs,android::dataloader::StatusListenerPtr listener,android::dataloader::ServiceConnectorPtr service,android::dataloader::ServiceParamsPtr params)114 LegacyDataLoader* ManagedDataLoader::create(JavaVM* jvm,
115 android::dataloader::FilesystemConnectorPtr ifs,
116 android::dataloader::StatusListenerPtr listener,
117 android::dataloader::ServiceConnectorPtr service,
118 android::dataloader::ServiceParamsPtr params) {
119 JNIEnv* env = GetJNIEnvironment(jvm);
120 const auto& jni = jniIds(env);
121
122 jobject dlp = env->NewObject(jni.dataLoaderParams, jni.dataLoaderParamsConstruct, params);
123 jobject ifsc =
124 env->NewObject(jni.fileSystemConnector, jni.fileSystemConnectorConstruct, (jlong)ifs);
125
126 auto dataLoader = env->CallObjectMethod(service, jni.dataLoaderServiceOnCreateDataLoader, dlp);
127 if (!dataLoader) {
128 LOG(ERROR) << "Failed to create Java DataLoader.";
129 return nullptr;
130 }
131 if (env->ExceptionCheck()) {
132 return nullptr;
133 }
134 if (!env->CallBooleanMethod(dataLoader, jni.dataLoaderOnCreate, dlp, ifsc)) {
135 return nullptr;
136 }
137
138 return new ManagedDataLoader(jvm, env->NewGlobalRef(dataLoader));
139 }
140
onDestroy()141 void ManagedDataLoader::onDestroy() {
142 CHECK(mDataLoader);
143
144 JNIEnv* env = GetJNIEnvironment(mJvm);
145
146 env->DeleteGlobalRef(mDataLoader);
147 mDataLoader = nullptr;
148 }
149
toJavaArrayList(JNIEnv * env,const JniIds & jni,const DataLoaderInstallationFiles & files)150 static jobject toJavaArrayList(JNIEnv* env, const JniIds& jni,
151 const DataLoaderInstallationFiles& files) {
152 jobject arrayList =
153 env->NewObject(jni.arrayList, jni.arrayListCtor, static_cast<jint>(files.size()));
154 for (const auto& file : files) {
155 const auto location(file.location);
156 const auto size(file.size);
157
158 jstring name = env->NewStringUTF(file.name);
159 jbyteArray metadata = env->NewByteArray(file.metadata.size);
160 if (metadata != nullptr) {
161 env->SetByteArrayRegion(metadata, 0, file.metadata.size,
162 (const jbyte*)file.metadata.data);
163 }
164
165 jobject jfile = env->NewObject(jni.installationFile, jni.installationFileCtor, location,
166 name, size, metadata, nullptr);
167 env->CallBooleanMethod(arrayList, jni.arrayListAdd, jfile);
168 }
169 return arrayList;
170 }
171
onPrepareImage(DataLoaderInstallationFiles addedFiles)172 bool ManagedDataLoader::onPrepareImage(DataLoaderInstallationFiles addedFiles) {
173 CHECK(mDataLoader);
174
175 auto env = GetOrAttachJNIEnvironment(mJvm);
176 const auto& jni = jniIds(env);
177
178 jobject jaddedFiles = toJavaArrayList(env, jni, addedFiles);
179 return env->CallBooleanMethod(mDataLoader, jni.dataLoaderOnPrepareImage, jaddedFiles, nullptr);
180 }
181
ManagedDataLoaderFactory()182 ManagedDataLoaderFactory::ManagedDataLoaderFactory() {
183 ::DataLoaderFactory::onCreate =
184 [](::DataLoaderFactory* self, const ::DataLoaderParams* ndkParams,
185 ::DataLoaderFilesystemConnectorPtr fsConnector,
186 ::DataLoaderStatusListenerPtr statusListener, ::DataLoaderServiceVmPtr vm,
187 ::DataLoaderServiceConnectorPtr serviceConnector,
188 ::DataLoaderServiceParamsPtr serviceParams) -> ::DataLoader* {
189 return reinterpret_cast<::DataLoader*>(
190 ManagedDataLoader::create(vm, static_cast<FilesystemConnector*>(fsConnector),
191 static_cast<StatusListener*>(statusListener),
192 serviceConnector, serviceParams));
193 };
194 }
195
196 } // namespace android::dataloader
197