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 "incfs-dataloaderconnector"
17
18 #include <android-base/logging.h>
19 #include <nativehelper/JNIPlatformHelp.h>
20 #include <nativehelper/scoped_local_ref.h>
21 #include <nativehelper/scoped_utf_chars.h>
22 #include <fcntl.h>
23 #include <sys/stat.h>
24 #include <utils/Looper.h>
25
26 #include <thread>
27 #include <unordered_map>
28
29 #include "JNIHelpers.h"
30 #include "ManagedDataLoader.h"
31 #include "dataloader.h"
32 #include "incfs.h"
33
34 namespace {
35
36 using namespace android::dataloader;
37 using namespace std::literals;
38
39 using FileId = android::incfs::FileId;
40 using RawMetadata = android::incfs::RawMetadata;
41 using UniqueControl = android::incfs::UniqueControl;
42
43 struct JniIds {
44 struct {
45 jint DATA_LOADER_CREATED;
46 jint DATA_LOADER_DESTROYED;
47 jint DATA_LOADER_STARTED;
48 jint DATA_LOADER_STOPPED;
49 jint DATA_LOADER_IMAGE_READY;
50 jint DATA_LOADER_IMAGE_NOT_READY;
51 jint DATA_LOADER_UNAVAILABLE;
52 jint DATA_LOADER_UNRECOVERABLE;
53
54 jint DATA_LOADER_TYPE_NONE;
55 jint DATA_LOADER_TYPE_STREAMING;
56 jint DATA_LOADER_TYPE_INCREMENTAL;
57
58 jint DATA_LOADER_LOCATION_DATA_APP;
59 jint DATA_LOADER_LOCATION_MEDIA_OBB;
60 jint DATA_LOADER_LOCATION_MEDIA_DATA;
61 } constants;
62
63 jmethodID parcelFileDescriptorGetFileDescriptor;
64
65 jfieldID incremental;
66 jfieldID service;
67 jfieldID callback;
68
69 jfieldID controlCmd;
70 jfieldID controlPendingReads;
71 jfieldID controlLog;
72
73 jfieldID paramsType;
74 jfieldID paramsPackageName;
75 jfieldID paramsClassName;
76 jfieldID paramsArguments;
77
78 jclass listener;
79 jmethodID listenerOnStatusChanged;
80
81 jmethodID callbackControlWriteData;
82
83 jmethodID listGet;
84 jmethodID listSize;
85
86 jfieldID installationFileLocation;
87 jfieldID installationFileName;
88 jfieldID installationFileLengthBytes;
89 jfieldID installationFileMetadata;
90
91 jmethodID incrementalServiceConnectorSetStorageParams;
92
JniIds__anon3f07e4fb0111::JniIds93 JniIds(JNIEnv* env) {
94 listener = (jclass)env->NewGlobalRef(
95 FindClassOrDie(env, "android/content/pm/IDataLoaderStatusListener"));
96 listenerOnStatusChanged = GetMethodIDOrDie(env, listener, "onStatusChanged", "(II)V");
97
98 constants.DATA_LOADER_CREATED =
99 GetStaticIntFieldValueOrDie(env, listener, "DATA_LOADER_CREATED");
100 constants.DATA_LOADER_DESTROYED =
101 GetStaticIntFieldValueOrDie(env, listener, "DATA_LOADER_DESTROYED");
102 constants.DATA_LOADER_STARTED =
103 GetStaticIntFieldValueOrDie(env, listener, "DATA_LOADER_STARTED");
104 constants.DATA_LOADER_STOPPED =
105 GetStaticIntFieldValueOrDie(env, listener, "DATA_LOADER_STOPPED");
106 constants.DATA_LOADER_IMAGE_READY =
107 GetStaticIntFieldValueOrDie(env, listener, "DATA_LOADER_IMAGE_READY");
108 constants.DATA_LOADER_IMAGE_NOT_READY =
109 GetStaticIntFieldValueOrDie(env, listener, "DATA_LOADER_IMAGE_NOT_READY");
110
111 constants.DATA_LOADER_UNAVAILABLE =
112 GetStaticIntFieldValueOrDie(env, listener, "DATA_LOADER_UNAVAILABLE");
113 constants.DATA_LOADER_UNRECOVERABLE =
114 GetStaticIntFieldValueOrDie(env, listener, "DATA_LOADER_UNRECOVERABLE");
115
116 CHECK(constants.DATA_LOADER_UNRECOVERABLE == DATA_LOADER_UNRECOVERABLE);
117
118 auto packageInstaller = (jclass)FindClassOrDie(env, "android/content/pm/PackageInstaller");
119
120 constants.DATA_LOADER_TYPE_NONE =
121 GetStaticIntFieldValueOrDie(env, packageInstaller, "DATA_LOADER_TYPE_NONE");
122 constants.DATA_LOADER_TYPE_STREAMING =
123 GetStaticIntFieldValueOrDie(env, packageInstaller, "DATA_LOADER_TYPE_STREAMING");
124 constants.DATA_LOADER_TYPE_INCREMENTAL =
125 GetStaticIntFieldValueOrDie(env, packageInstaller, "DATA_LOADER_TYPE_INCREMENTAL");
126
127 CHECK(constants.DATA_LOADER_TYPE_NONE == DATA_LOADER_TYPE_NONE);
128 CHECK(constants.DATA_LOADER_TYPE_STREAMING == DATA_LOADER_TYPE_STREAMING);
129 CHECK(constants.DATA_LOADER_TYPE_INCREMENTAL == DATA_LOADER_TYPE_INCREMENTAL);
130
131 constants.DATA_LOADER_LOCATION_DATA_APP =
132 GetStaticIntFieldValueOrDie(env, packageInstaller, "LOCATION_DATA_APP");
133 constants.DATA_LOADER_LOCATION_MEDIA_OBB =
134 GetStaticIntFieldValueOrDie(env, packageInstaller, "LOCATION_MEDIA_OBB");
135 constants.DATA_LOADER_LOCATION_MEDIA_DATA =
136 GetStaticIntFieldValueOrDie(env, packageInstaller, "LOCATION_MEDIA_DATA");
137
138 CHECK(constants.DATA_LOADER_LOCATION_DATA_APP == DATA_LOADER_LOCATION_DATA_APP);
139 CHECK(constants.DATA_LOADER_LOCATION_MEDIA_OBB == DATA_LOADER_LOCATION_MEDIA_OBB);
140 CHECK(constants.DATA_LOADER_LOCATION_MEDIA_DATA == DATA_LOADER_LOCATION_MEDIA_DATA);
141
142 auto parcelFileDescriptor = FindClassOrDie(env, "android/os/ParcelFileDescriptor");
143 parcelFileDescriptorGetFileDescriptor =
144 GetMethodIDOrDie(env, parcelFileDescriptor, "getFileDescriptor",
145 "()Ljava/io/FileDescriptor;");
146
147 auto control = FindClassOrDie(env, "android/content/pm/FileSystemControlParcel");
148 incremental =
149 GetFieldIDOrDie(env, control, "incremental",
150 "Landroid/os/incremental/IncrementalFileSystemControlParcel;");
151 service = GetFieldIDOrDie(env, control, "service",
152 "Landroid/os/incremental/IIncrementalServiceConnector;");
153 callback =
154 GetFieldIDOrDie(env, control, "callback",
155 "Landroid/content/pm/IPackageInstallerSessionFileSystemConnector;");
156
157 auto incControl =
158 FindClassOrDie(env, "android/os/incremental/IncrementalFileSystemControlParcel");
159 controlCmd = GetFieldIDOrDie(env, incControl, "cmd", "Landroid/os/ParcelFileDescriptor;");
160 controlPendingReads = GetFieldIDOrDie(env, incControl, "pendingReads",
161 "Landroid/os/ParcelFileDescriptor;");
162 controlLog = GetFieldIDOrDie(env, incControl, "log", "Landroid/os/ParcelFileDescriptor;");
163
164 auto params = FindClassOrDie(env, "android/content/pm/DataLoaderParamsParcel");
165 paramsType = GetFieldIDOrDie(env, params, "type", "I");
166 paramsPackageName = GetFieldIDOrDie(env, params, "packageName", "Ljava/lang/String;");
167 paramsClassName = GetFieldIDOrDie(env, params, "className", "Ljava/lang/String;");
168 paramsArguments = GetFieldIDOrDie(env, params, "arguments", "Ljava/lang/String;");
169
170 auto callbackControl =
171 FindClassOrDie(env,
172 "android/content/pm/IPackageInstallerSessionFileSystemConnector");
173 callbackControlWriteData =
174 GetMethodIDOrDie(env, callbackControl, "writeData",
175 "(Ljava/lang/String;JJLandroid/os/ParcelFileDescriptor;)V");
176
177 auto list = (jclass)FindClassOrDie(env, "java/util/List");
178 listGet = GetMethodIDOrDie(env, list, "get", "(I)Ljava/lang/Object;");
179 listSize = GetMethodIDOrDie(env, list, "size", "()I");
180
181 auto installationFileParcel =
182 (jclass)FindClassOrDie(env, "android/content/pm/InstallationFileParcel");
183 installationFileLocation = GetFieldIDOrDie(env, installationFileParcel, "location", "I");
184 installationFileName =
185 GetFieldIDOrDie(env, installationFileParcel, "name", "Ljava/lang/String;");
186 installationFileLengthBytes = GetFieldIDOrDie(env, installationFileParcel, "size", "J");
187 installationFileMetadata = GetFieldIDOrDie(env, installationFileParcel, "metadata", "[B");
188
189 auto incrementalServiceConnector =
190 FindClassOrDie(env, "android/os/incremental/IIncrementalServiceConnector");
191 incrementalServiceConnectorSetStorageParams =
192 GetMethodIDOrDie(env, incrementalServiceConnector, "setStorageParams", "(Z)I");
193 }
194 };
195
getJavaVM(JNIEnv * env)196 JavaVM* getJavaVM(JNIEnv* env) {
197 CHECK(env);
198 JavaVM* jvm = nullptr;
199 env->GetJavaVM(&jvm);
200 CHECK(jvm);
201 return jvm;
202 }
203
jniIds(JNIEnv * env)204 const JniIds& jniIds(JNIEnv* env) {
205 static const JniIds ids(env);
206 return ids;
207 }
208
reportStatusViaCallback(JNIEnv * env,jobject listener,jint storageId,jint status)209 bool reportStatusViaCallback(JNIEnv* env, jobject listener, jint storageId, jint status) {
210 if (listener == nullptr) {
211 ALOGE("No listener object to talk to IncrementalService. "
212 "DataLoaderId=%d, "
213 "status=%d",
214 storageId, status);
215 return false;
216 }
217
218 const auto& jni = jniIds(env);
219
220 env->CallVoidMethod(listener, jni.listenerOnStatusChanged, storageId, status);
221 ALOGI("Reported status back to IncrementalService. DataLoaderId=%d, "
222 "status=%d",
223 storageId, status);
224
225 return true;
226 }
227
228 class DataLoaderConnector;
229 using DataLoaderConnectorPtr = std::shared_ptr<DataLoaderConnector>;
230 using DataLoaderConnectorsMap = std::unordered_map<int, DataLoaderConnectorPtr>;
231
232 struct Globals {
Globals__anon3f07e4fb0111::Globals233 Globals() {
234 managedDataLoaderFactory = new details::DataLoaderFactoryImpl(
235 [](auto jvm, auto) { return std::make_unique<ManagedDataLoader>(jvm); });
236 }
237
238 DataLoaderFactory* managedDataLoaderFactory = nullptr;
239 DataLoaderFactory* dataLoaderFactory = nullptr;
240
241 std::mutex dataLoaderConnectorsLock;
242 // id->DataLoader map
243 DataLoaderConnectorsMap dataLoaderConnectors GUARDED_BY(dataLoaderConnectorsLock);
244
245 std::atomic_bool stopped;
246 std::thread pendingReadsLooperThread;
247 std::thread logLooperThread;
248 std::vector<ReadInfo> pendingReads;
249 std::vector<ReadInfo> pageReads;
250 };
251
globals()252 static Globals& globals() {
253 static Globals globals;
254 return globals;
255 }
256
257 struct IncFsLooper : public android::Looper {
IncFsLooper__anon3f07e4fb0111::IncFsLooper258 IncFsLooper() : Looper(/*allowNonCallbacks=*/false) {}
~IncFsLooper__anon3f07e4fb0111::IncFsLooper259 ~IncFsLooper() {}
260 };
261
pendingReadsLooper()262 static android::Looper& pendingReadsLooper() {
263 static IncFsLooper pendingReadsLooper;
264 return pendingReadsLooper;
265 }
266
logLooper()267 static android::Looper& logLooper() {
268 static IncFsLooper logLooper;
269 return logLooper;
270 }
271
272 struct DataLoaderParamsPair {
273 static DataLoaderParamsPair createFromManaged(JNIEnv* env, jobject params);
274
dataLoaderParams__anon3f07e4fb0111::DataLoaderParamsPair275 const android::dataloader::DataLoaderParams& dataLoaderParams() const {
276 return mDataLoaderParams;
277 }
ndkDataLoaderParams__anon3f07e4fb0111::DataLoaderParamsPair278 const ::DataLoaderParams& ndkDataLoaderParams() const { return mNDKDataLoaderParams; }
279
280 private:
281 DataLoaderParamsPair(android::dataloader::DataLoaderParams&& dataLoaderParams);
282
283 android::dataloader::DataLoaderParams mDataLoaderParams;
284 ::DataLoaderParams mNDKDataLoaderParams;
285 };
286
287 static constexpr auto kPendingReadsBufferSize = 256;
288
289 class DataLoaderConnector : public FilesystemConnector, public StatusListener {
290 public:
DataLoaderConnector(JNIEnv * env,jobject service,jint storageId,UniqueControl control,jobject serviceConnector,jobject callbackControl,jobject listener)291 DataLoaderConnector(JNIEnv* env, jobject service, jint storageId, UniqueControl control,
292 jobject serviceConnector, jobject callbackControl, jobject listener)
293 : mJvm(getJavaVM(env)),
294 mService(env->NewGlobalRef(service)),
295 mServiceConnector(env->NewGlobalRef(serviceConnector)),
296 mCallbackControl(env->NewGlobalRef(callbackControl)),
297 mListener(env->NewGlobalRef(listener)),
298 mStorageId(storageId),
299 mControl(std::move(control)) {
300 CHECK(mJvm != nullptr);
301 }
302 DataLoaderConnector(const DataLoaderConnector&) = delete;
303 DataLoaderConnector(const DataLoaderConnector&&) = delete;
~DataLoaderConnector()304 virtual ~DataLoaderConnector() {
305 JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
306
307 env->DeleteGlobalRef(mService);
308 env->DeleteGlobalRef(mServiceConnector);
309 env->DeleteGlobalRef(mCallbackControl);
310 env->DeleteGlobalRef(mListener);
311 } // to avoid delete-non-virtual-dtor
312
onCreate(const DataLoaderParamsPair & params,jobject managedParams)313 bool onCreate(const DataLoaderParamsPair& params, jobject managedParams) {
314 CHECK(mDataLoader == nullptr);
315
316 if (auto factory = globals().dataLoaderFactory) {
317 // Let's try the non-default first.
318 mDataLoader = factory->onCreate(factory, ¶ms.ndkDataLoaderParams(), this, this,
319 mJvm, mService, managedParams);
320 if (checkAndClearJavaException(__func__)) {
321 return false;
322 }
323 }
324
325 if (!mDataLoader) {
326 // Didn't work, let's try the default.
327 auto factory = globals().managedDataLoaderFactory;
328 mDataLoader = factory->onCreate(factory, ¶ms.ndkDataLoaderParams(), this, this,
329 mJvm, mService, managedParams);
330 if (checkAndClearJavaException(__func__)) {
331 return false;
332 }
333 }
334
335 if (!mDataLoader) {
336 return false;
337 }
338
339 return true;
340 }
onStart()341 bool onStart() {
342 CHECK(mDataLoader);
343 bool result = mDataLoader->onStart(mDataLoader);
344 if (checkAndClearJavaException(__func__)) {
345 result = false;
346 }
347 mRunning = result;
348 return result;
349 }
onStop()350 void onStop() {
351 CHECK(mDataLoader);
352
353 // Stopping both loopers and waiting for them to exit - we should be able to acquire/release
354 // both mutexes.
355 mRunning = false;
356 std::lock_guard{mPendingReadsLooperBusy}; // NOLINT
357 std::lock_guard{mLogLooperBusy}; // NOLINT
358
359 mDataLoader->onStop(mDataLoader);
360 checkAndClearJavaException(__func__);
361 }
onDestroy()362 void onDestroy() {
363 CHECK(mDataLoader);
364 mDataLoader->onDestroy(mDataLoader);
365 checkAndClearJavaException(__func__);
366 }
367
onPrepareImage(const DataLoaderInstallationFiles & addedFiles)368 bool onPrepareImage(const DataLoaderInstallationFiles& addedFiles) {
369 CHECK(mDataLoader);
370 bool result =
371 mDataLoader->onPrepareImage(mDataLoader, addedFiles.data(), addedFiles.size());
372 if (checkAndClearJavaException(__func__)) {
373 result = false;
374 }
375 return result;
376 }
377
onPendingReadsLooperEvent(std::vector<ReadInfo> & pendingReads)378 int onPendingReadsLooperEvent(std::vector<ReadInfo>& pendingReads) {
379 CHECK(mDataLoader);
380 std::lock_guard lock{mPendingReadsLooperBusy};
381 while (mRunning.load(std::memory_order_relaxed)) {
382 pendingReads.resize(kPendingReadsBufferSize);
383 if (android::incfs::waitForPendingReads(mControl, 0ms, &pendingReads) !=
384 android::incfs::WaitResult::HaveData ||
385 pendingReads.empty()) {
386 return 1;
387 }
388 mDataLoader->onPendingReads(mDataLoader, pendingReads.data(), pendingReads.size());
389 }
390 return 1;
391 }
onLogLooperEvent(std::vector<ReadInfo> & pageReads)392 int onLogLooperEvent(std::vector<ReadInfo>& pageReads) {
393 CHECK(mDataLoader);
394 std::lock_guard lock{mLogLooperBusy};
395 while (mRunning.load(std::memory_order_relaxed)) {
396 pageReads.clear();
397 if (android::incfs::waitForPageReads(mControl, 0ms, &pageReads) !=
398 android::incfs::WaitResult::HaveData ||
399 pageReads.empty()) {
400 return 1;
401 }
402 mDataLoader->onPageReads(mDataLoader, pageReads.data(), pageReads.size());
403 }
404 return 1;
405 }
406
writeData(jstring name,jlong offsetBytes,jlong lengthBytes,jobject incomingFd) const407 void writeData(jstring name, jlong offsetBytes, jlong lengthBytes, jobject incomingFd) const {
408 CHECK(mCallbackControl);
409 JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
410 const auto& jni = jniIds(env);
411 env->CallVoidMethod(mCallbackControl, jni.callbackControlWriteData, name, offsetBytes,
412 lengthBytes, incomingFd);
413 }
414
openForSpecialOps(FileId fid) const415 android::incfs::UniqueFd openForSpecialOps(FileId fid) const {
416 return android::incfs::openForSpecialOps(mControl, fid);
417 }
418
writeBlocks(Span<const IncFsDataBlock> blocks) const419 int writeBlocks(Span<const IncFsDataBlock> blocks) const {
420 return android::incfs::writeBlocks(blocks);
421 }
422
getRawMetadata(FileId fid,char buffer[],size_t * bufferSize) const423 int getRawMetadata(FileId fid, char buffer[], size_t* bufferSize) const {
424 return IncFs_GetMetadataById(mControl, fid, buffer, bufferSize);
425 }
426
setParams(DataLoaderFilesystemParams params) const427 bool setParams(DataLoaderFilesystemParams params) const {
428 CHECK(mServiceConnector);
429 JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
430 const auto& jni = jniIds(env);
431 int result = env->CallIntMethod(mServiceConnector,
432 jni.incrementalServiceConnectorSetStorageParams,
433 params.readLogsEnabled);
434 if (result != 0) {
435 LOG(ERROR) << "setStorageParams failed with error: " << result;
436 }
437 if (checkAndClearJavaException(__func__)) {
438 return false;
439 }
440 return (result == 0);
441 }
442
reportStatus(DataLoaderStatus status)443 bool reportStatus(DataLoaderStatus status) {
444 if (status < DATA_LOADER_FIRST_STATUS || DATA_LOADER_LAST_STATUS < status) {
445 ALOGE("Unable to report invalid status. status=%d", status);
446 return false;
447 }
448 JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
449 return reportStatusViaCallback(env, mListener, mStorageId, status);
450 }
451
checkAndClearJavaException(std::string_view method) const452 bool checkAndClearJavaException(std::string_view method) const {
453 JNIEnv* env = GetOrAttachJNIEnvironment(mJvm);
454
455 if (!env->ExceptionCheck()) {
456 return false;
457 }
458
459 LOG(ERROR) << "Java exception during DataLoader::" << method;
460 env->ExceptionDescribe();
461 env->ExceptionClear();
462 return true;
463 }
464
control() const465 const UniqueControl& control() const { return mControl; }
getListenerLocalRef(JNIEnv * env) const466 jobject getListenerLocalRef(JNIEnv* env) const { return env->NewLocalRef(mListener); }
467
468 private:
469 JavaVM* const mJvm;
470 jobject const mService;
471 jobject const mServiceConnector;
472 jobject const mCallbackControl;
473 jobject const mListener;
474
475 jint const mStorageId;
476 UniqueControl const mControl;
477
478 ::DataLoader* mDataLoader = nullptr;
479
480 std::mutex mPendingReadsLooperBusy;
481 std::mutex mLogLooperBusy;
482 std::atomic<bool> mRunning{false};
483 };
484
onPendingReadsLooperEvent(int fd,int events,void * data)485 static int onPendingReadsLooperEvent(int fd, int events, void* data) {
486 if (globals().stopped) {
487 // No more listeners.
488 return 0;
489 }
490 auto&& dataLoaderConnector = (DataLoaderConnector*)data;
491 return dataLoaderConnector->onPendingReadsLooperEvent(globals().pendingReads);
492 }
493
onLogLooperEvent(int fd,int events,void * data)494 static int onLogLooperEvent(int fd, int events, void* data) {
495 if (globals().stopped) {
496 // No more listeners.
497 return 0;
498 }
499 auto&& dataLoaderConnector = (DataLoaderConnector*)data;
500 return dataLoaderConnector->onLogLooperEvent(globals().pageReads);
501 }
502
createFdFromManaged(JNIEnv * env,jobject pfd)503 static int createFdFromManaged(JNIEnv* env, jobject pfd) {
504 if (!pfd) {
505 return -1;
506 }
507
508 const auto& jni = jniIds(env);
509 auto managedFd = env->CallObjectMethod(pfd, jni.parcelFileDescriptorGetFileDescriptor);
510 return fcntl(jniGetFDFromFileDescriptor(env, managedFd), F_DUPFD_CLOEXEC, 0);
511 }
512
createServiceConnector(JNIEnv * env,jobject managedControl)513 static jobject createServiceConnector(JNIEnv* env, jobject managedControl) {
514 const auto& jni = jniIds(env);
515 return env->GetObjectField(managedControl, jni.service);
516 }
517
createCallbackControl(JNIEnv * env,jobject managedControl)518 static jobject createCallbackControl(JNIEnv* env, jobject managedControl) {
519 const auto& jni = jniIds(env);
520 return env->GetObjectField(managedControl, jni.callback);
521 }
522
createIncFsControlFromManaged(JNIEnv * env,jobject managedControl)523 static UniqueControl createIncFsControlFromManaged(JNIEnv* env, jobject managedControl) {
524 const auto& jni = jniIds(env);
525 auto managedIncControl = env->GetObjectField(managedControl, jni.incremental);
526 if (!managedIncControl) {
527 return UniqueControl();
528 }
529 auto cmd = createFdFromManaged(env, env->GetObjectField(managedIncControl, jni.controlCmd));
530 auto pr = createFdFromManaged(env,
531 env->GetObjectField(managedIncControl, jni.controlPendingReads));
532 auto log = createFdFromManaged(env, env->GetObjectField(managedIncControl, jni.controlLog));
533 return android::incfs::createControl(cmd, pr, log);
534 }
535
DataLoaderParamsPair(android::dataloader::DataLoaderParams && dataLoaderParams)536 DataLoaderParamsPair::DataLoaderParamsPair(android::dataloader::DataLoaderParams&& dataLoaderParams)
537 : mDataLoaderParams(std::move(dataLoaderParams)) {
538 mNDKDataLoaderParams.type = mDataLoaderParams.type();
539 mNDKDataLoaderParams.packageName = mDataLoaderParams.packageName().c_str();
540 mNDKDataLoaderParams.className = mDataLoaderParams.className().c_str();
541 mNDKDataLoaderParams.arguments = mDataLoaderParams.arguments().c_str();
542 }
543
createFromManaged(JNIEnv * env,jobject managedParams)544 DataLoaderParamsPair DataLoaderParamsPair::createFromManaged(JNIEnv* env, jobject managedParams) {
545 const auto& jni = jniIds(env);
546
547 const DataLoaderType type = (DataLoaderType)env->GetIntField(managedParams, jni.paramsType);
548
549 ScopedLocalRef<jstring> paramsPackageName(env,
550 GetStringField(env, managedParams,
551 jni.paramsPackageName));
552 ScopedLocalRef<jstring> paramsClassName(env,
553 GetStringField(env, managedParams,
554 jni.paramsClassName));
555 ScopedLocalRef<jstring> paramsArguments(env,
556 GetStringField(env, managedParams,
557 jni.paramsArguments));
558 ScopedUtfChars package(env, paramsPackageName.get());
559 ScopedUtfChars className(env, paramsClassName.get());
560 ScopedUtfChars arguments(env, paramsArguments.get());
561 return DataLoaderParamsPair(android::dataloader::DataLoaderParams(type, package.c_str(),
562 className.c_str(),
563 arguments.c_str()));
564 }
565
pendingReadsLooperThread()566 static void pendingReadsLooperThread() {
567 constexpr auto kTimeoutMsecs = 60 * 1000;
568 while (!globals().stopped) {
569 pendingReadsLooper().pollAll(kTimeoutMsecs);
570 }
571 }
572
logLooperThread()573 static void logLooperThread() {
574 constexpr auto kTimeoutMsecs = 60 * 1000;
575 while (!globals().stopped) {
576 logLooper().pollAll(kTimeoutMsecs);
577 }
578 }
579
pathFromFd(int fd)580 static std::string pathFromFd(int fd) {
581 static constexpr char fdNameFormat[] = "/proc/self/fd/%d";
582 char fdNameBuffer[NELEM(fdNameFormat) + 11 + 1]; // max int length + '\0'
583 snprintf(fdNameBuffer, NELEM(fdNameBuffer), fdNameFormat, fd);
584
585 std::string res;
586 // lstat() is supposed to return us exactly the needed buffer size, but
587 // somehow it may also return a smaller (but still >0) st_size field.
588 // That's why let's only use it for the initial estimate.
589 struct stat st = {};
590 if (::lstat(fdNameBuffer, &st) || st.st_size == 0) {
591 st.st_size = PATH_MAX;
592 }
593 auto bufSize = st.st_size;
594 for (;;) {
595 res.resize(bufSize + 1, '\0');
596 auto size = ::readlink(fdNameBuffer, &res[0], res.size());
597 if (size < 0) {
598 return {};
599 }
600 if (size > bufSize) {
601 // File got renamed in between lstat() and readlink() calls? Retry.
602 bufSize *= 2;
603 continue;
604 }
605 res.resize(size);
606 return res;
607 }
608 }
609
610 } // namespace
611
DataLoader_Initialize(struct::DataLoaderFactory * factory)612 void DataLoader_Initialize(struct ::DataLoaderFactory* factory) {
613 CHECK(factory) << "DataLoader factory is invalid.";
614 globals().dataLoaderFactory = factory;
615 }
616
DataLoader_FilesystemConnector_writeData(DataLoaderFilesystemConnectorPtr ifs,jstring name,jlong offsetBytes,jlong lengthBytes,jobject incomingFd)617 void DataLoader_FilesystemConnector_writeData(DataLoaderFilesystemConnectorPtr ifs, jstring name,
618 jlong offsetBytes, jlong lengthBytes,
619 jobject incomingFd) {
620 auto connector = static_cast<DataLoaderConnector*>(ifs);
621 return connector->writeData(name, offsetBytes, lengthBytes, incomingFd);
622 }
623
DataLoader_FilesystemConnector_openForSpecialOps(DataLoaderFilesystemConnectorPtr ifs,IncFsFileId fid)624 int DataLoader_FilesystemConnector_openForSpecialOps(DataLoaderFilesystemConnectorPtr ifs,
625 IncFsFileId fid) {
626 auto connector = static_cast<DataLoaderConnector*>(ifs);
627 return connector->openForSpecialOps(fid).release();
628 }
629
DataLoader_FilesystemConnector_writeBlocks(DataLoaderFilesystemConnectorPtr ifs,const IncFsDataBlock blocks[],int blocksCount)630 int DataLoader_FilesystemConnector_writeBlocks(DataLoaderFilesystemConnectorPtr ifs,
631 const IncFsDataBlock blocks[], int blocksCount) {
632 auto connector = static_cast<DataLoaderConnector*>(ifs);
633 return connector->writeBlocks({blocks, static_cast<size_t>(blocksCount)});
634 }
635
DataLoader_FilesystemConnector_getRawMetadata(DataLoaderFilesystemConnectorPtr ifs,IncFsFileId fid,char buffer[],size_t * bufferSize)636 int DataLoader_FilesystemConnector_getRawMetadata(DataLoaderFilesystemConnectorPtr ifs,
637 IncFsFileId fid, char buffer[],
638 size_t* bufferSize) {
639 auto connector = static_cast<DataLoaderConnector*>(ifs);
640 return connector->getRawMetadata(fid, buffer, bufferSize);
641 }
642
DataLoader_FilesystemConnector_setParams(DataLoaderFilesystemConnectorPtr ifs,DataLoaderFilesystemParams params)643 bool DataLoader_FilesystemConnector_setParams(DataLoaderFilesystemConnectorPtr ifs,
644 DataLoaderFilesystemParams params) {
645 auto connector = static_cast<DataLoaderConnector*>(ifs);
646 return connector->setParams(params);
647 }
648
DataLoader_StatusListener_reportStatus(DataLoaderStatusListenerPtr listener,DataLoaderStatus status)649 int DataLoader_StatusListener_reportStatus(DataLoaderStatusListenerPtr listener,
650 DataLoaderStatus status) {
651 auto connector = static_cast<DataLoaderConnector*>(listener);
652 return connector->reportStatus(status);
653 }
654
DataLoaderService_OnCreate(JNIEnv * env,jobject service,jint storageId,jobject control,jobject params,jobject listener)655 bool DataLoaderService_OnCreate(JNIEnv* env, jobject service, jint storageId, jobject control,
656 jobject params, jobject listener) {
657 {
658 std::lock_guard lock{globals().dataLoaderConnectorsLock};
659 auto dlIt = globals().dataLoaderConnectors.find(storageId);
660 if (dlIt != globals().dataLoaderConnectors.end()) {
661 ALOGI("id(%d): already exist, skipping creation.", storageId);
662 return true;
663 }
664 }
665 auto nativeControl = createIncFsControlFromManaged(env, control);
666 ALOGI("DataLoader::create1 cmd: %d|%s", nativeControl.cmd(),
667 pathFromFd(nativeControl.cmd()).c_str());
668 ALOGI("DataLoader::create1 pendingReads: %d|%s", nativeControl.pendingReads(),
669 pathFromFd(nativeControl.pendingReads()).c_str());
670 ALOGI("DataLoader::create1 log: %d|%s", nativeControl.logs(),
671 pathFromFd(nativeControl.logs()).c_str());
672
673 auto nativeParams = DataLoaderParamsPair::createFromManaged(env, params);
674 ALOGI("DataLoader::create2: %d|%s|%s|%s", nativeParams.dataLoaderParams().type(),
675 nativeParams.dataLoaderParams().packageName().c_str(),
676 nativeParams.dataLoaderParams().className().c_str(),
677 nativeParams.dataLoaderParams().arguments().c_str());
678
679 auto serviceConnector = createServiceConnector(env, control);
680 auto callbackControl = createCallbackControl(env, control);
681
682 auto reportUnavailable = [env, storageId](jobject listener) {
683 const auto& jni = jniIds(env);
684 reportStatusViaCallback(env, listener, storageId, jni.constants.DATA_LOADER_UNAVAILABLE);
685 };
686 // By default, it's disabled. Need to assign listener to enable.
687 std::unique_ptr<_jobject, decltype(reportUnavailable)>
688 reportUnavailableOnExit(nullptr, reportUnavailable);
689
690 auto dataLoaderConnector =
691 std::make_unique<DataLoaderConnector>(env, service, storageId, std::move(nativeControl),
692 serviceConnector, callbackControl, listener);
693 {
694 std::lock_guard lock{globals().dataLoaderConnectorsLock};
695 auto [dlIt, dlInserted] =
696 globals().dataLoaderConnectors.try_emplace(storageId,
697 std::move(dataLoaderConnector));
698 if (!dlInserted) {
699 ALOGE("id(%d): already exist, skipping creation.", storageId);
700 return false;
701 }
702 if (!dlIt->second->onCreate(nativeParams, params)) {
703 globals().dataLoaderConnectors.erase(dlIt);
704 // Enable the reporter.
705 reportUnavailableOnExit.reset(listener);
706 return false;
707 }
708 }
709
710 const auto& jni = jniIds(env);
711 reportStatusViaCallback(env, listener, storageId, jni.constants.DATA_LOADER_CREATED);
712
713 return true;
714 }
715
DataLoaderService_OnStart(JNIEnv * env,jint storageId)716 bool DataLoaderService_OnStart(JNIEnv* env, jint storageId) {
717 auto destroyAndReportUnavailable = [env, storageId](jobject listener) {
718 // Because of the MT the installer can call commit and recreate/restart dataLoader before
719 // system server has a change to destroy it.
720 DataLoaderService_OnDestroy(env, storageId);
721 const auto& jni = jniIds(env);
722 reportStatusViaCallback(env, listener, storageId, jni.constants.DATA_LOADER_UNAVAILABLE);
723 };
724 // By default, it's disabled. Need to assign listener to enable.
725 std::unique_ptr<_jobject, decltype(destroyAndReportUnavailable)>
726 destroyAndReportUnavailableOnExit(nullptr, destroyAndReportUnavailable);
727
728 const UniqueControl* control;
729 jobject listener;
730 DataLoaderConnectorPtr dataLoaderConnector;
731 {
732 std::lock_guard lock{globals().dataLoaderConnectorsLock};
733 auto dlIt = globals().dataLoaderConnectors.find(storageId);
734 if (dlIt == globals().dataLoaderConnectors.end()) {
735 ALOGE("Failed to start id(%d): not found", storageId);
736 return false;
737 }
738
739 listener = dlIt->second->getListenerLocalRef(env);
740
741 dataLoaderConnector = dlIt->second;
742 if (!dataLoaderConnector->onStart()) {
743 ALOGE("Failed to start id(%d): onStart returned false", storageId);
744 destroyAndReportUnavailableOnExit.reset(listener);
745 return false;
746 }
747
748 control = &(dataLoaderConnector->control());
749
750 // Create loopers while we are under lock.
751 if (control->pendingReads() >= 0 && !globals().pendingReadsLooperThread.joinable()) {
752 pendingReadsLooper();
753 globals().pendingReadsLooperThread = std::thread(&pendingReadsLooperThread);
754 }
755 if (control->logs() >= 0 && !globals().logLooperThread.joinable()) {
756 logLooper();
757 globals().logLooperThread = std::thread(&logLooperThread);
758 }
759 }
760
761 if (control->pendingReads() >= 0) {
762 pendingReadsLooper().addFd(control->pendingReads(), android::Looper::POLL_CALLBACK,
763 android::Looper::EVENT_INPUT, &onPendingReadsLooperEvent,
764 dataLoaderConnector.get());
765 pendingReadsLooper().wake();
766 }
767
768 if (control->logs() >= 0) {
769 logLooper().addFd(control->logs(), android::Looper::POLL_CALLBACK,
770 android::Looper::EVENT_INPUT, &onLogLooperEvent,
771 dataLoaderConnector.get());
772 logLooper().wake();
773 }
774
775 const auto& jni = jniIds(env);
776 reportStatusViaCallback(env, listener, storageId, jni.constants.DATA_LOADER_STARTED);
777
778 return true;
779 }
780
DataLoaderService_OnStop_NoStatus(JNIEnv * env,jint storageId)781 jobject DataLoaderService_OnStop_NoStatus(JNIEnv* env, jint storageId) {
782 const UniqueControl* control;
783 {
784 std::lock_guard lock{globals().dataLoaderConnectorsLock};
785 auto dlIt = globals().dataLoaderConnectors.find(storageId);
786 if (dlIt == globals().dataLoaderConnectors.end()) {
787 return nullptr;
788 }
789 control = &(dlIt->second->control());
790 }
791
792 if (control->pendingReads() >= 0) {
793 pendingReadsLooper().removeFd(control->pendingReads());
794 pendingReadsLooper().wake();
795 }
796 if (control->logs() >= 0) {
797 logLooper().removeFd(control->logs());
798 logLooper().wake();
799 }
800
801 jobject listener = nullptr;
802 {
803 std::lock_guard lock{globals().dataLoaderConnectorsLock};
804 auto dlIt = globals().dataLoaderConnectors.find(storageId);
805 if (dlIt == globals().dataLoaderConnectors.end()) {
806 ALOGI("Failed to stop id(%d): not found", storageId);
807 return nullptr;
808 }
809
810 listener = dlIt->second->getListenerLocalRef(env);
811
812 auto&& dataLoaderConnector = dlIt->second;
813 dataLoaderConnector->onStop();
814 }
815 return listener;
816 }
817
DataLoaderService_OnStop(JNIEnv * env,jint storageId)818 bool DataLoaderService_OnStop(JNIEnv* env, jint storageId) {
819 auto listener = DataLoaderService_OnStop_NoStatus(env, storageId);
820 if (listener == nullptr) {
821 ALOGI("Failed to stop id(%d): not found", storageId);
822 return true;
823 }
824
825 const auto& jni = jniIds(env);
826 reportStatusViaCallback(env, listener, storageId, jni.constants.DATA_LOADER_STOPPED);
827
828 return true;
829 }
830
DataLoaderService_OnDestroy_NoStatus(JNIEnv * env,jint storageId)831 jobject DataLoaderService_OnDestroy_NoStatus(JNIEnv* env, jint storageId) {
832 jobject listener = DataLoaderService_OnStop_NoStatus(env, storageId);
833 if (!listener) {
834 return nullptr;
835 }
836
837 {
838 std::lock_guard lock{globals().dataLoaderConnectorsLock};
839 auto dlIt = globals().dataLoaderConnectors.find(storageId);
840 if (dlIt == globals().dataLoaderConnectors.end()) {
841 return nullptr;
842 }
843
844 auto&& dataLoaderConnector = dlIt->second;
845 dataLoaderConnector->onDestroy();
846 globals().dataLoaderConnectors.erase(dlIt);
847 }
848
849 return listener;
850 }
851
DataLoaderService_OnDestroy(JNIEnv * env,jint storageId)852 bool DataLoaderService_OnDestroy(JNIEnv* env, jint storageId) {
853 jobject listener = DataLoaderService_OnDestroy_NoStatus(env, storageId);
854 if (!listener) {
855 ALOGI("Failed to remove id(%d): not found", storageId);
856 return true;
857 }
858
859 const auto& jni = jniIds(env);
860 reportStatusViaCallback(env, listener, storageId, jni.constants.DATA_LOADER_DESTROYED);
861
862 return true;
863 }
864
865 struct DataLoaderInstallationFilesPair {
866 static DataLoaderInstallationFilesPair createFromManaged(JNIEnv* env, jobjectArray jfiles);
867
868 using Files = std::vector<android::dataloader::DataLoaderInstallationFile>;
filesDataLoaderInstallationFilesPair869 const Files& files() const { return mFiles; }
870
871 using NDKFiles = std::vector<::DataLoaderInstallationFile>;
ndkFilesDataLoaderInstallationFilesPair872 const NDKFiles& ndkFiles() const { return mNDKFiles; }
873
874 private:
875 DataLoaderInstallationFilesPair(Files&& files);
876
877 Files mFiles;
878 NDKFiles mNDKFiles;
879 };
880
createFromManaged(JNIEnv * env,jobjectArray jfiles)881 DataLoaderInstallationFilesPair DataLoaderInstallationFilesPair::createFromManaged(
882 JNIEnv* env, jobjectArray jfiles) {
883 const auto& jni = jniIds(env);
884
885 // jfiles is a Java array of InstallationFileParcel
886 auto size = env->GetArrayLength(jfiles);
887 DataLoaderInstallationFilesPair::Files files;
888 files.reserve(size);
889
890 for (int i = 0; i < size; ++i) {
891 ScopedLocalRef<jobject> jfile(env, env->GetObjectArrayElement(jfiles, i));
892
893 DataLoaderLocation location =
894 (DataLoaderLocation)env->GetIntField(jfile.get(), jni.installationFileLocation);
895 ScopedUtfChars name(env, GetStringField(env, jfile.get(), jni.installationFileName));
896 IncFsSize size = env->GetLongField(jfile.get(), jni.installationFileLengthBytes);
897
898 ScopedLocalRef<jbyteArray> jmetadataBytes(env,
899 GetByteArrayField(env, jfile.get(),
900 jni.installationFileMetadata));
901 auto metadataElements = env->GetByteArrayElements(jmetadataBytes.get(), nullptr);
902 auto metadataLength = env->GetArrayLength(jmetadataBytes.get());
903 RawMetadata metadata(metadataElements, metadataElements + metadataLength);
904 env->ReleaseByteArrayElements(jmetadataBytes.get(), metadataElements, 0);
905
906 files.emplace_back(location, name.c_str(), size, std::move(metadata));
907 }
908
909 return DataLoaderInstallationFilesPair(std::move(files));
910 }
911
DataLoaderInstallationFilesPair(Files && files)912 DataLoaderInstallationFilesPair::DataLoaderInstallationFilesPair(Files&& files)
913 : mFiles(std::move(files)) {
914 const auto size = mFiles.size();
915 mNDKFiles.resize(size);
916 for (size_t i = 0; i < size; ++i) {
917 const auto& file = mFiles[i];
918 auto&& ndkFile = mNDKFiles[i];
919
920 ndkFile.location = file.location();
921 ndkFile.name = file.name().c_str();
922 ndkFile.size = file.size();
923 ndkFile.metadata.data = file.metadata().data();
924 ndkFile.metadata.size = file.metadata().size();
925 }
926 }
927
DataLoaderService_OnPrepareImage(JNIEnv * env,jint storageId,jobjectArray addedFiles,jobjectArray removedFiles)928 bool DataLoaderService_OnPrepareImage(JNIEnv* env, jint storageId, jobjectArray addedFiles,
929 jobjectArray removedFiles) {
930 jobject listener;
931 DataLoaderConnectorPtr dataLoaderConnector;
932 {
933 std::lock_guard lock{globals().dataLoaderConnectorsLock};
934 auto dlIt = globals().dataLoaderConnectors.find(storageId);
935 if (dlIt == globals().dataLoaderConnectors.end()) {
936 ALOGE("Failed to handle onPrepareImage for id(%d): not found", storageId);
937 return false;
938 }
939 listener = dlIt->second->getListenerLocalRef(env);
940 dataLoaderConnector = dlIt->second;
941 }
942
943 auto addedFilesPair = DataLoaderInstallationFilesPair::createFromManaged(env, addedFiles);
944 bool result = dataLoaderConnector->onPrepareImage(addedFilesPair.ndkFiles());
945
946 const auto& jni = jniIds(env);
947 reportStatusViaCallback(env, listener, storageId,
948 result ? jni.constants.DATA_LOADER_IMAGE_READY
949 : jni.constants.DATA_LOADER_IMAGE_NOT_READY);
950
951 return result;
952 }
953