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::__anonb0c510dd0111::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)94 ManagedDataLoader::ManagedDataLoader(JavaVM* jvm) : mJvm(jvm) {
95     CHECK(mJvm);
96 }
97 
onCreate(const android::dataloader::DataLoaderParams &,android::dataloader::FilesystemConnectorPtr ifs,android::dataloader::StatusListenerPtr listener,android::dataloader::ServiceConnectorPtr service,android::dataloader::ServiceParamsPtr params)98 bool ManagedDataLoader::onCreate(const android::dataloader::DataLoaderParams&,
99                                  android::dataloader::FilesystemConnectorPtr ifs,
100                                  android::dataloader::StatusListenerPtr listener,
101                                  android::dataloader::ServiceConnectorPtr service,
102                                  android::dataloader::ServiceParamsPtr params) {
103     CHECK(!mDataLoader);
104 
105     JNIEnv* env = GetJNIEnvironment(mJvm);
106     const auto& jni = jniIds(env);
107 
108     jobject dlp = env->NewObject(jni.dataLoaderParams, jni.dataLoaderParamsConstruct, params);
109     jobject ifsc =
110             env->NewObject(jni.fileSystemConnector, jni.fileSystemConnectorConstruct, (jlong)ifs);
111 
112     auto dataLoader = env->CallObjectMethod(service, jni.dataLoaderServiceOnCreateDataLoader, dlp);
113     if (!dataLoader) {
114         LOG(ERROR) << "Failed to create Java DataLoader.";
115         return false;
116     }
117     if (env->ExceptionCheck()) {
118         return false;
119     }
120 
121     mDataLoader = env->NewGlobalRef(dataLoader);
122     return env->CallBooleanMethod(mDataLoader, jni.dataLoaderOnCreate, dlp, ifsc);
123 }
124 
onDestroy()125 void ManagedDataLoader::onDestroy() {
126     CHECK(mDataLoader);
127 
128     JNIEnv* env = GetJNIEnvironment(mJvm);
129 
130     env->DeleteGlobalRef(mDataLoader);
131     mDataLoader = nullptr;
132 }
133 
toJavaArrayList(JNIEnv * env,const JniIds & jni,const DataLoaderInstallationFiles & files)134 static jobject toJavaArrayList(JNIEnv* env, const JniIds& jni,
135                                const DataLoaderInstallationFiles& files) {
136     jobject arrayList =
137             env->NewObject(jni.arrayList, jni.arrayListCtor, static_cast<jint>(files.size()));
138     for (const auto& file : files) {
139         const auto location(file.location);
140         const auto size(file.size);
141 
142         jstring name = env->NewStringUTF(file.name);
143         jbyteArray metadata = env->NewByteArray(file.metadata.size);
144         if (metadata != nullptr) {
145             env->SetByteArrayRegion(metadata, 0, file.metadata.size,
146                                     (const jbyte*)file.metadata.data);
147         }
148 
149         jobject jfile = env->NewObject(jni.installationFile, jni.installationFileCtor, location,
150                                        name, size, metadata, nullptr);
151         env->CallBooleanMethod(arrayList, jni.arrayListAdd, jfile);
152     }
153     return arrayList;
154 }
155 
onPrepareImage(DataLoaderInstallationFiles addedFiles)156 bool ManagedDataLoader::onPrepareImage(DataLoaderInstallationFiles addedFiles) {
157     CHECK(mDataLoader);
158 
159     auto env = GetOrAttachJNIEnvironment(mJvm);
160     const auto& jni = jniIds(env);
161 
162     jobject jaddedFiles = toJavaArrayList(env, jni, addedFiles);
163     return env->CallBooleanMethod(mDataLoader, jni.dataLoaderOnPrepareImage, jaddedFiles, nullptr);
164 }
165 
166 } // namespace android::dataloader
167