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
JniIds__anon295076e60111::JniIds91 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
getJavaVM(JNIEnv * env)194 JavaVM* getJavaVM(JNIEnv* env) {
195 CHECK(env);
196 JavaVM* jvm = nullptr;
197 env->GetJavaVM(&jvm);
198 CHECK(jvm);
199 return jvm;
200 }
201
jniIds(JNIEnv * env)202 const JniIds& jniIds(JNIEnv* env) {
203 static const JniIds ids(env);
204 return ids;
205 }
206
reportStatusViaCallback(JNIEnv * env,jobject listener,jint storageId,jint status)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 {
Globals__anon295076e60111::Globals231 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
globals()250 static Globals& globals() {
251 static Globals globals;
252 return globals;
253 }
254
255 struct IncFsLooper : public android::Looper {
IncFsLooper__anon295076e60111::IncFsLooper256 IncFsLooper() : Looper(/*allowNonCallbacks=*/false) {}
~IncFsLooper__anon295076e60111::IncFsLooper257 ~IncFsLooper() {}
258 };
259
pendingReadsLooper()260 static android::Looper& pendingReadsLooper() {
261 static IncFsLooper pendingReadsLooper;
262 return pendingReadsLooper;
263 }
264
logLooper()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
dataLoaderParams__anon295076e60111::DataLoaderParamsPair273 const android::dataloader::DataLoaderParams& dataLoaderParams() const {
274 return mDataLoaderParams;
275 }
ndkDataLoaderParams__anon295076e60111::DataLoaderParamsPair276 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:
DataLoaderConnector(JNIEnv * env,jobject service,jint storageId,UniqueControl control,jobject serviceConnector,jobject callbackControl,jobject listener)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;
~DataLoaderConnector()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
onCreate(const DataLoaderParamsPair & params,jobject managedParams)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, ¶ms.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, ¶ms.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 }
onStart()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 }
onStop()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 }
onDestroy()360 void onDestroy() {
361 CHECK(mDataLoader);
362 mDataLoader->onDestroy(mDataLoader);
363 checkAndClearJavaException(__func__);
364 }
365
onPrepareImage(const DataLoaderInstallationFiles & addedFiles)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
onPendingReadsLooperEvent(std::vector<ReadInfo> & pendingReads)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 }
onLogLooperEvent(std::vector<ReadInfo> & pageReads)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
writeData(jstring name,jlong offsetBytes,jlong lengthBytes,jobject incomingFd) const405 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
openForSpecialOps(FileId fid) const413 android::incfs::UniqueFd openForSpecialOps(FileId fid) const {
414 return android::incfs::openForSpecialOps(mControl, fid);
415 }
416
writeBlocks(Span<const IncFsDataBlock> blocks) const417 int writeBlocks(Span<const IncFsDataBlock> blocks) const {
418 return android::incfs::writeBlocks(blocks);
419 }
420
getRawMetadata(FileId fid,char buffer[],size_t * bufferSize) const421 int getRawMetadata(FileId fid, char buffer[], size_t* bufferSize) const {
422 return IncFs_GetMetadataById(mControl, fid, buffer, bufferSize);
423 }
424
setParams(DataLoaderFilesystemParams params) const425 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
reportStatus(DataLoaderStatus status)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
checkAndClearJavaException(std::string_view method) const450 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
control() const463 const UniqueControl& control() const { return mControl; }
getListenerLocalRef(JNIEnv * env) const464 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
onPendingReadsLooperEvent(int fd,int events,void * data)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
onLogLooperEvent(int fd,int events,void * data)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
createFdFromManaged(JNIEnv * env,jobject pfd)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
createServiceConnector(JNIEnv * env,jobject managedControl)511 static jobject createServiceConnector(JNIEnv* env, jobject managedControl) {
512 const auto& jni = jniIds(env);
513 return env->GetObjectField(managedControl, jni.service);
514 }
515
createCallbackControl(JNIEnv * env,jobject managedControl)516 static jobject createCallbackControl(JNIEnv* env, jobject managedControl) {
517 const auto& jni = jniIds(env);
518 return env->GetObjectField(managedControl, jni.callback);
519 }
520
createIncFsControlFromManaged(JNIEnv * env,jobject managedControl)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
DataLoaderParamsPair(android::dataloader::DataLoaderParams && dataLoaderParams)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
createFromManaged(JNIEnv * env,jobject managedParams)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
pendingReadsLooperThread()563 static void pendingReadsLooperThread() {
564 constexpr auto kTimeoutMsecs = 60 * 1000;
565 while (!globals().stopped) {
566 pendingReadsLooper().pollAll(kTimeoutMsecs);
567 }
568 }
569
logLooperThread()570 static void logLooperThread() {
571 constexpr auto kTimeoutMsecs = 60 * 1000;
572 while (!globals().stopped) {
573 logLooper().pollAll(kTimeoutMsecs);
574 }
575 }
576
pathFromFd(int fd)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
DataLoader_Initialize(struct::DataLoaderFactory * factory)609 void DataLoader_Initialize(struct ::DataLoaderFactory* factory) {
610 CHECK(factory) << "DataLoader factory is invalid.";
611 globals().dataLoaderFactory = factory;
612 }
613
DataLoader_FilesystemConnector_writeData(DataLoaderFilesystemConnectorPtr ifs,jstring name,jlong offsetBytes,jlong lengthBytes,jobject incomingFd)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
DataLoader_FilesystemConnector_openForSpecialOps(DataLoaderFilesystemConnectorPtr ifs,IncFsFileId fid)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
DataLoader_FilesystemConnector_writeBlocks(DataLoaderFilesystemConnectorPtr ifs,const IncFsDataBlock blocks[],int blocksCount)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
DataLoader_FilesystemConnector_getRawMetadata(DataLoaderFilesystemConnectorPtr ifs,IncFsFileId fid,char buffer[],size_t * bufferSize)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
DataLoader_FilesystemConnector_setParams(DataLoaderFilesystemConnectorPtr ifs,DataLoaderFilesystemParams params)640 bool DataLoader_FilesystemConnector_setParams(DataLoaderFilesystemConnectorPtr ifs,
641 DataLoaderFilesystemParams params) {
642 auto connector = static_cast<DataLoaderConnector*>(ifs);
643 return connector->setParams(params);
644 }
645
DataLoader_StatusListener_reportStatus(DataLoaderStatusListenerPtr listener,DataLoaderStatus status)646 int DataLoader_StatusListener_reportStatus(DataLoaderStatusListenerPtr listener,
647 DataLoaderStatus status) {
648 auto connector = static_cast<DataLoaderConnector*>(listener);
649 return connector->reportStatus(status);
650 }
651
DataLoaderService_OnCreate(JNIEnv * env,jobject service,jint storageId,jobject control,jobject params,jobject listener)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
DataLoaderService_OnStart(JNIEnv * env,jint storageId)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
DataLoaderService_OnStop_NoStatus(JNIEnv * env,jint storageId)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
DataLoaderService_OnStop(JNIEnv * env,jint storageId)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
DataLoaderService_OnDestroy_NoStatus(JNIEnv * env,jint storageId)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
DataLoaderService_OnDestroy(JNIEnv * env,jint storageId)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>;
filesDataLoaderInstallationFilesPair866 const Files& files() const { return mFiles; }
867
868 using NDKFiles = std::vector<::DataLoaderInstallationFile>;
ndkFilesDataLoaderInstallationFilesPair869 const NDKFiles& ndkFiles() const { return mNDKFiles; }
870
871 private:
872 DataLoaderInstallationFilesPair(Files&& files);
873
874 Files mFiles;
875 NDKFiles mNDKFiles;
876 };
877
createFromManaged(JNIEnv * env,jobjectArray jfiles)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
DataLoaderInstallationFilesPair(Files && files)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
DataLoaderService_OnPrepareImage(JNIEnv * env,jint storageId,jobjectArray addedFiles,jobjectArray removedFiles)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