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