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