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, ¶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 } 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