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, &params.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, &params.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