blob: 4c0f55f2bf23e15fb481693b83cb3e3c252f58c0 [file] [log] [blame]
Songchun Fan1a52cf72019-12-05 13:00:47 -08001/*
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
Alex Buynytskyy89247d22019-12-11 12:07:23 -080017#define LOG_TAG "dataloader-jni"
Songchun Fan1a52cf72019-12-05 13:00:47 -080018
19#include <vector>
20
21#include "core_jni_helpers.h"
Alex Buynytskyy89247d22019-12-11 12:07:23 -080022#include "dataloader_ndk.h"
Songchun Fan1a52cf72019-12-05 13:00:47 -080023#include "jni.h"
24
25namespace android {
26namespace {
27
28struct JniIds {
29 jfieldID dataBlockFileIno;
30 jfieldID dataBlockBlockIndex;
31 jfieldID dataBlockDataBytes;
32 jfieldID dataBlockCompressionType;
33
34 JniIds(JNIEnv* env) {
35 const auto dataBlock =
36 FindClassOrDie(env,
37 "android/service/incremental/"
38 "IncrementalDataLoaderService$FileSystemConnector$DataBlock");
39 dataBlockFileIno = GetFieldIDOrDie(env, dataBlock, "mFileIno", "J");
40 dataBlockBlockIndex =
41 GetFieldIDOrDie(env, dataBlock, "mBlockIndex", "I");
42 dataBlockDataBytes = GetFieldIDOrDie(env, dataBlock, "mDataBytes", "[B");
43 dataBlockCompressionType =
44 GetFieldIDOrDie(env, dataBlock, "mCompressionType", "I");
45 }
46};
47
48const JniIds& jniIds(JNIEnv* env) {
49 static const JniIds ids(env);
50 return ids;
51}
52
53class ScopedJniArrayCritical {
54public:
55 ScopedJniArrayCritical(JNIEnv* env, jarray array) : mEnv(env), mArr(array) {
56 mPtr = array ? env->GetPrimitiveArrayCritical(array, nullptr) : nullptr;
57 }
58 ~ScopedJniArrayCritical() {
59 if (mPtr) {
60 mEnv->ReleasePrimitiveArrayCritical(mArr, mPtr, 0);
61 mPtr = nullptr;
62 }
63 }
64
65 ScopedJniArrayCritical(const ScopedJniArrayCritical&) = delete;
66 void operator=(const ScopedJniArrayCritical&) = delete;
67
68 ScopedJniArrayCritical(ScopedJniArrayCritical&& other)
69 : mEnv(other.mEnv),
70 mArr(std::exchange(mArr, nullptr)),
71 mPtr(std::exchange(mPtr, nullptr)) {}
72 ScopedJniArrayCritical& operator=(ScopedJniArrayCritical&& other) {
73 mEnv = other.mEnv;
74 mArr = std::exchange(other.mArr, nullptr);
75 mPtr = std::exchange(other.mPtr, nullptr);
76 return *this;
77 }
78
79 void* ptr() const { return mPtr; }
80 jsize size() const { return mArr ? mEnv->GetArrayLength(mArr) : 0; }
81
82private:
83 JNIEnv* mEnv;
84 jarray mArr;
85 void* mPtr;
86};
87
88static jboolean nativeCreateDataLoader(JNIEnv* env,
89 jobject thiz,
90 jint storageId,
91 jobject control,
92 jobject params,
93 jobject callback) {
94 ALOGE("nativeCreateDataLoader: %p/%d, %d, %p, %p, %p", thiz,
95 env->GetObjectRefType(thiz), storageId, params, control, callback);
Alex Buynytskyy89247d22019-12-11 12:07:23 -080096 return DataLoaderService_OnCreate(env, thiz,
Songchun Fan1a52cf72019-12-05 13:00:47 -080097 storageId, control, params, callback);
98}
99
100static jboolean nativeStartDataLoader(JNIEnv* env,
101 jobject thiz,
102 jint storageId) {
103 ALOGE("nativeStartDataLoader: %p/%d, %d", thiz, env->GetObjectRefType(thiz),
104 storageId);
Alex Buynytskyy89247d22019-12-11 12:07:23 -0800105 return DataLoaderService_OnStart(storageId);
Songchun Fan1a52cf72019-12-05 13:00:47 -0800106}
107
108static jboolean nativeStopDataLoader(JNIEnv* env,
109 jobject thiz,
110 jint storageId) {
111 ALOGE("nativeStopDataLoader: %p/%d, %d", thiz, env->GetObjectRefType(thiz),
112 storageId);
Alex Buynytskyy89247d22019-12-11 12:07:23 -0800113 return DataLoaderService_OnStop(storageId);
Songchun Fan1a52cf72019-12-05 13:00:47 -0800114}
115
116static jboolean nativeDestroyDataLoader(JNIEnv* env,
117 jobject thiz,
118 jint storageId) {
119 ALOGE("nativeDestroyDataLoader: %p/%d, %d", thiz,
120 env->GetObjectRefType(thiz), storageId);
Alex Buynytskyy89247d22019-12-11 12:07:23 -0800121 return DataLoaderService_OnDestroy(storageId);
Songchun Fan1a52cf72019-12-05 13:00:47 -0800122}
123
124
125static jboolean nativeOnFileCreated(JNIEnv* env,
126 jobject thiz,
127 jint storageId,
128 jlong inode,
129 jbyteArray metadata) {
130 ALOGE("nativeOnFileCreated: %p/%d, %d", thiz,
131 env->GetObjectRefType(thiz), storageId);
Alex Buynytskyy89247d22019-12-11 12:07:23 -0800132 return DataLoaderService_OnFileCreated(storageId, inode, metadata);
Songchun Fan1a52cf72019-12-05 13:00:47 -0800133}
134
135static jboolean nativeIsFileRangeLoadedNode(JNIEnv* env,
136 jobject clazz,
137 jlong self,
138 jlong node,
139 jlong start,
140 jlong end) {
141 // TODO(b/136132412): implement this
142 return JNI_FALSE;
143}
144
145static jboolean nativeWriteMissingData(JNIEnv* env,
146 jobject clazz,
147 jlong self,
148 jobjectArray data_block,
149 jobjectArray hash_blocks) {
150 const auto& jni = jniIds(env);
151 auto length = env->GetArrayLength(data_block);
152 std::vector<incfs_new_data_block> instructions(length);
153
154 // May not call back into Java after even a single jniArrayCritical, so
155 // let's collect the Java pointers to byte buffers first and lock them in
156 // memory later.
157
158 std::vector<jbyteArray> blockBuffers(length);
159 for (int i = 0; i != length; ++i) {
160 auto& inst = instructions[i];
161 auto jniBlock = env->GetObjectArrayElement(data_block, i);
162 inst.file_ino = env->GetLongField(jniBlock, jni.dataBlockFileIno);
163 inst.block_index = env->GetIntField(jniBlock, jni.dataBlockBlockIndex);
164 blockBuffers[i] = (jbyteArray)env->GetObjectField(
165 jniBlock, jni.dataBlockDataBytes);
166 inst.compression = (incfs_compression_alg)env->GetIntField(
167 jniBlock, jni.dataBlockCompressionType);
168 }
169
170 std::vector<ScopedJniArrayCritical> jniScopedArrays;
171 jniScopedArrays.reserve(length);
172 for (int i = 0; i != length; ++i) {
173 auto buffer = blockBuffers[i];
174 jniScopedArrays.emplace_back(env, buffer);
175 auto& inst = instructions[i];
176 inst.data = (uint64_t)jniScopedArrays.back().ptr();
177 inst.data_len = jniScopedArrays.back().size();
178 }
179
Alex Buynytskyy89247d22019-12-11 12:07:23 -0800180 auto connector = (DataLoaderFilesystemConnectorPtr)self;
181 if (auto err = DataLoader_FilesystemConnector_writeBlocks(
Songchun Fan1a52cf72019-12-05 13:00:47 -0800182 connector, instructions.data(), length);
183 err < 0) {
184 jniScopedArrays.clear();
185 return JNI_FALSE;
186 }
187
188 return JNI_TRUE;
189}
190
191static jboolean nativeWriteSignerDataNode(JNIEnv* env,
192 jobject clazz,
193 jlong self,
194 jstring relative_path,
195 jbyteArray signer_data) {
196 // TODO(b/136132412): implement this
197 return JNI_TRUE;
198}
199
200static jbyteArray nativeGetFileMetadataNode(JNIEnv* env,
201 jobject clazz,
202 jlong self,
203 jlong inode) {
Alex Buynytskyy89247d22019-12-11 12:07:23 -0800204 auto connector = (DataLoaderFilesystemConnectorPtr)self;
Songchun Fan1a52cf72019-12-05 13:00:47 -0800205 std::vector<char> metadata(INCFS_MAX_FILE_ATTR_SIZE);
206 size_t size = metadata.size();
Alex Buynytskyy89247d22019-12-11 12:07:23 -0800207 if (DataLoader_FilesystemConnector_getRawMetadata(connector, inode,
Songchun Fan1a52cf72019-12-05 13:00:47 -0800208 metadata.data(), &size) < 0) {
209 size = 0;
210 }
211 metadata.resize(size);
212
213 auto buffer = env->NewByteArray(metadata.size());
214 env->SetByteArrayRegion(buffer, 0, metadata.size(),
215 (jbyte*)metadata.data());
216 return buffer;
217}
218
219static jbyteArray nativeGetFileInfoNode(JNIEnv* env,
220 jobject clazz,
221 jlong self,
222 jlong inode) {
223 // TODO(b/136132412): implement this
224 return nullptr;
225}
226
227static jboolean nativeReportStatus(JNIEnv* env,
228 jobject clazz,
229 jlong self,
230 jint status) {
Alex Buynytskyy89247d22019-12-11 12:07:23 -0800231 auto listener = (DataLoaderStatusListenerPtr)self;
232 return DataLoader_StatusListener_reportStatus(listener,
233 (DataLoaderStatus)status);
Songchun Fan1a52cf72019-12-05 13:00:47 -0800234}
235
236static const JNINativeMethod dlc_method_table[] = {
237 {"nativeCreateDataLoader",
238 "(ILandroid/os/incremental/IncrementalFileSystemControlParcel;"
239 "Landroid/os/incremental/IncrementalDataLoaderParamsParcel;"
240 "Landroid/content/pm/IDataLoaderStatusListener;)Z",
241 (void*)nativeCreateDataLoader},
242 {"nativeStartDataLoader", "(I)Z", (void*)nativeStartDataLoader},
243 {"nativeStopDataLoader", "(I)Z", (void*)nativeStopDataLoader},
244 {"nativeDestroyDataLoader", "(I)Z", (void*)nativeDestroyDataLoader},
245 {"nativeIsFileRangeLoadedNode", "(JJJJ)Z",
246 (void*)nativeIsFileRangeLoadedNode},
247 {"nativeWriteMissingData",
248 "(J[Landroid/service/incremental/"
249 "IncrementalDataLoaderService$FileSystemConnector$DataBlock;[Landroid/service/incremental/"
250 "IncrementalDataLoaderService$FileSystemConnector$HashBlock;)Z",
251 (void*)nativeWriteMissingData},
252 {"nativeWriteSignerDataNode", "(JJ[B)Z",
253 (void*)nativeWriteSignerDataNode},
254 {"nativeGetFileMetadataNode", "(JJ)[B",
255 (void*)nativeGetFileMetadataNode},
256 {"nativeGetFileInfoNode", "(JJ)[B", (void*)nativeGetFileInfoNode},
257 {"nativeReportStatus", "(JI)Z", (void*)nativeReportStatus},
258 {"nativeOnFileCreated", "(IJ[B)Z", (void*)nativeOnFileCreated},
259};
260
261} // namespace
262
Alex Buynytskyy89247d22019-12-11 12:07:23 -0800263int register_android_service_DataLoaderService(JNIEnv* env) {
Songchun Fan1a52cf72019-12-05 13:00:47 -0800264 return jniRegisterNativeMethods(env,
265 "android/service/incremental/IncrementalDataLoaderService",
266 dlc_method_table, NELEM(dlc_method_table));
267}
268
269} // namespace android