chromium/chrome/browser/download/android/download_manager_service.cc

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/download/android/download_manager_service.h"

#include <memory>
#include <optional>

#include "base/android/callback_android.h"
#include "base/android/jni_string.h"
#include "base/android/path_utils.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/metrics/field_trial_params.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "chrome/browser/android/flags/chrome_cached_flags.h"
#include "chrome/browser/android/profile_key_startup_accessor.h"
#include "chrome/browser/download/android/download_controller.h"
#include "chrome/browser/download/android/download_startup_utils.h"
#include "chrome/browser/download/android/download_utils.h"
#include "chrome/browser/download/android/service/download_task_scheduler.h"
#include "chrome/browser/download/offline_item_utils.h"
#include "chrome/browser/download/simple_download_manager_coordinator_factory.h"
#include "chrome/browser/flags/android/chrome_feature_list.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_key.h"
#include "chrome/browser/profiles/profile_key_android.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_constants.h"
#include "components/download/network/android/network_status_listener_android.h"
#include "components/download/public/common/android/auto_resumption_handler.h"
#include "components/download/public/common/download_features.h"
#include "components/download/public/common/download_item.h"
#include "components/download/public/common/download_item_impl.h"
#include "components/download/public/common/download_stats.h"
#include "components/download/public/common/simple_download_manager_coordinator.h"
#include "components/download/public/common/url_download_handler_factory.h"
#include "components/download/public/task/task_manager_impl.h"
#include "components/offline_items_collection/core/android/offline_item_bridge.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/download_item_utils.h"
#include "content/public/browser/download_request_utils.h"
#include "net/url_request/referrer_policy.h"
#include "third_party/blink/public/common/mime_util/mime_util.h"
#include "url/android/gurl_android.h"
#include "url/origin.h"

// Must come after all headers that specialize FromJniType() / ToJniType().
#include "chrome/android/chrome_jni_headers/DownloadItem_jni.h"
#include "chrome/android/chrome_jni_headers/DownloadManagerService_jni.h"
#include "chrome/browser/download/android/jni_headers/DownloadInfo_jni.h"

using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
using offline_items_collection::android::OfflineItemBridge;

namespace {

// The remaining time for a download item if it cannot be calculated.
constexpr int64_t kUnknownRemainingTime = -1;

// Finch flag for controlling auto resumption limit.
int kDefaultAutoResumptionLimit = 5;
const char kAutoResumptionLimitParamName[] = "AutoResumptionLimit";

bool ShouldShowDownloadItem(download::DownloadItem* item) {
  return !item->IsTemporary() && !item->IsTransient();
}

ScopedJavaLocalRef<jobject> JNI_DownloadManagerService_CreateJavaDownloadItem(
    JNIEnv* env,
    download::DownloadItem* item) {
  DCHECK(!item->IsTransient());
  return Java_DownloadItem_createDownloadItem(
      env, DownloadManagerService::CreateJavaDownloadInfo(env, item),
      item->GetStartTime().InMillisecondsSinceUnixEpoch(),
      item->GetEndTime().InMillisecondsSinceUnixEpoch(),
      item->GetFileExternallyRemoved());
}

void RenameItemCallback(
    const base::android::ScopedJavaGlobalRef<jobject> j_callback,
    download::DownloadItem::DownloadRenameResult result) {
  base::android::RunIntCallbackAndroid(
      j_callback,
      static_cast<int32_t>(
          OfflineItemUtils::ConvertDownloadRenameResultToRenameResult(result)));
}

bool IsReducedModeProfileKey(ProfileKey* profile_key) {
  return profile_key == ProfileKeyStartupAccessor::GetInstance()->profile_key();
}

}  // namespace

// static
void DownloadManagerService::CreateAutoResumptionHandler() {
  auto network_listener =
      std::make_unique<download::NetworkStatusListenerAndroid>();
  auto task_scheduler =
      std::make_unique<download::android::DownloadTaskScheduler>();
  auto task_manager =
      std::make_unique<download::TaskManagerImpl>(std::move(task_scheduler));
  auto config = std::make_unique<download::AutoResumptionHandler::Config>();
  config->auto_resumption_size_limit =
      DownloadUtils::GetAutoResumptionSizeLimit();
  config->is_auto_resumption_enabled_in_native = true;
  download::AutoResumptionHandler::Create(
      std::move(network_listener), std::move(task_manager), std::move(config),
      base::DefaultClock::GetInstance());
}

// static
void DownloadManagerService::OnDownloadCanceled(
    download::DownloadItem* download,
    bool has_no_external_storage) {
  if (download->IsTransient()) {
    LOG(WARNING) << "Transient download should not have user interaction!";
    return;
  }

  // Inform the user in Java UI about file writing failures.
  JNIEnv* env = base::android::AttachCurrentThread();

  ScopedJavaLocalRef<jobject> j_item =
      JNI_DownloadManagerService_CreateJavaDownloadItem(env, download);
  Java_DownloadManagerService_onDownloadItemCanceled(env, j_item,
                                                     has_no_external_storage);
}

// static
DownloadManagerService* DownloadManagerService::GetInstance() {
  return base::Singleton<DownloadManagerService>::get();
}

// static
ScopedJavaLocalRef<jobject> DownloadManagerService::CreateJavaDownloadInfo(
    JNIEnv* env,
    download::DownloadItem* item) {
  base::TimeDelta time_delta;
  bool time_remaining_known = item->TimeRemaining(&time_delta);
  GURL original_url = item->GetOriginalUrl().SchemeIs(url::kDataScheme)
                          ? GURL()
                          : item->GetOriginalUrl();
  content::BrowserContext* browser_context =
      content::DownloadItemUtils::GetBrowserContext(item);

  base::android::ScopedJavaLocalRef<jobject> otr_profile_id;
  if (browser_context && browser_context->IsOffTheRecord()) {
    Profile* profile = Profile::FromBrowserContext(browser_context);
    otr_profile_id = profile->GetOTRProfileID().ConvertToJavaOTRProfileID(env);
  }

  return Java_DownloadInfo_createDownloadInfo(
      env, item->GetGuid(), item->GetFileNameToReportUser().value(),
      item->GetTargetFilePath().value(), item->GetURL(), item->GetMimeType(),
      item->GetReceivedBytes(), item->GetTotalBytes(), otr_profile_id,
      item->GetState(), item->PercentComplete(), item->IsPaused(),
      DownloadUtils::IsDownloadUserInitiated(item), item->CanResume(),
      item->IsParallelDownload(), original_url, item->GetReferrerUrl(),
      time_remaining_known ? time_delta.InMilliseconds()
                           : kUnknownRemainingTime,
      item->GetLastAccessTime().InMillisecondsSinceUnixEpoch(),
      item->IsDangerous(),
      static_cast<int>(
          OfflineItemUtils::ConvertDownloadInterruptReasonToFailState(
              item->GetLastReason())));
}

static jlong JNI_DownloadManagerService_Init(JNIEnv* env,
                                             const JavaParamRef<jobject>& jobj,
                                             jboolean is_full_browser_started) {
  DownloadManagerService* service = DownloadManagerService::GetInstance();
  service->Init(env, jobj, is_full_browser_started);
  return reinterpret_cast<intptr_t>(service);
}

DownloadManagerService::DownloadManagerService()
    : is_manager_initialized_(false), is_pending_downloads_loaded_(false) {}

DownloadManagerService::~DownloadManagerService() {}

void DownloadManagerService::Init(JNIEnv* env,
                                  jobject obj,
                                  bool is_profile_added) {
  java_ref_.Reset(env, obj);
  if (is_profile_added) {
    OnProfileAdded(
        ProfileManager::GetActiveUserProfile()->GetOriginalProfile());
  } else {
    // In reduced mode, only non-incognito downloads should be loaded.
    ResetCoordinatorIfNeeded(
        DownloadStartupUtils::EnsureDownloadSystemInitialized(nullptr));
  }
}

void DownloadManagerService::OnProfileAdded(JNIEnv* env,
                                            jobject obj,
                                            Profile* profile) {
  OnProfileAdded(profile);
}

void DownloadManagerService::OnProfileAdded(Profile* profile) {
  InitializeForProfile(profile->GetProfileKey());
  observed_profiles_.AddObservation(profile);
  for (Profile* otr : profile->GetAllOffTheRecordProfiles())
    InitializeForProfile(otr->GetProfileKey());
}

void DownloadManagerService::OnOffTheRecordProfileCreated(
    Profile* off_the_record) {
  InitializeForProfile(off_the_record->GetProfileKey());
}

void DownloadManagerService::OpenDownload(download::DownloadItem* download,
                                          int source) {
  if (java_ref_.is_null())
    return;

  JNIEnv* env = base::android::AttachCurrentThread();
  ScopedJavaLocalRef<jobject> j_item =
      JNI_DownloadManagerService_CreateJavaDownloadItem(env, download);

  Java_DownloadManagerService_openDownloadItem(env, java_ref_, j_item, source);
}

void DownloadManagerService::HandleOMADownload(download::DownloadItem* download,
                                               int64_t system_download_id) {
  if (java_ref_.is_null())
    return;

  JNIEnv* env = base::android::AttachCurrentThread();
  ScopedJavaLocalRef<jobject> j_item =
      JNI_DownloadManagerService_CreateJavaDownloadItem(env, download);

  Java_DownloadManagerService_handleOMADownload(env, java_ref_, j_item,
                                                system_download_id);
}

void DownloadManagerService::OpenDownload(
    JNIEnv* env,
    jobject obj,
    std::string& download_guid,
    const JavaParamRef<jobject>& j_profile_key,
    jint source) {
  if (!is_manager_initialized_)
    return;

  download::DownloadItem* item = GetDownload(
      download_guid, ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key));
  if (!item)
    return;

  OpenDownload(item, source);
}

void DownloadManagerService::OpenDownloadsPage(
    Profile* profile,
    DownloadOpenSource download_open_source) {
  if (java_ref_.is_null() || !profile)
    return;

  JNIEnv* env = base::android::AttachCurrentThread();
  if (profile->IsIncognitoProfile()) {
    profile->GetOTRProfileID().ConvertToJavaOTRProfileID(env);
  }
  Java_DownloadManagerService_openDownloadsPage(
      env,
      profile->IsIncognitoProfile()
          ? profile->GetOTRProfileID().ConvertToJavaOTRProfileID(env)
          : nullptr,
      static_cast<int>(download_open_source));
}

void DownloadManagerService::ResumeDownload(
    JNIEnv* env,
    jobject obj,
    std::string& download_guid,
    const JavaParamRef<jobject>& j_profile_key) {
  ProfileKey* profile_key =
      ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key);
  if (is_pending_downloads_loaded_ || profile_key->IsOffTheRecord()) {
    ResumeDownloadInternal(download_guid, profile_key);
  } else {
    EnqueueDownloadAction(download_guid, RESUME);
  }
}

void DownloadManagerService::PauseDownload(
    JNIEnv* env,
    jobject obj,
    std::string& download_guid,
    const JavaParamRef<jobject>& j_profile_key) {
  ProfileKey* profile_key =
      ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key);
  if (is_pending_downloads_loaded_ || profile_key->IsOffTheRecord())
    PauseDownloadInternal(download_guid, profile_key);
  else
    EnqueueDownloadAction(download_guid, PAUSE);
}

void DownloadManagerService::RemoveDownload(
    JNIEnv* env,
    jobject obj,
    std::string& download_guid,
    const JavaParamRef<jobject>& j_profile_key) {
  ProfileKey* profile_key =
      ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key);
  if (is_manager_initialized_ || profile_key->IsOffTheRecord())
    RemoveDownloadInternal(download_guid, profile_key);
  else
    EnqueueDownloadAction(download_guid, REMOVE);
}

void DownloadManagerService::GetAllDownloads(
    JNIEnv* env,
    const JavaParamRef<jobject>& obj,
    const JavaParamRef<jobject>& j_profile_key) {
  ProfileKey* profile_key =
      ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key);
  if (is_manager_initialized_) {
    GetAllDownloadsInternal(profile_key);
    return;
  }

  // Full download manager is required for this call.
  GetDownloadManager(profile_key);
  profiles_with_pending_get_downloads_actions_.push_back(profile_key);
}

void DownloadManagerService::GetAllDownloadsInternal(ProfileKey* profile_key) {
  content::DownloadManager* manager = GetDownloadManager(profile_key);
  if (java_ref_.is_null() || !manager)
    return;

  content::DownloadManager::DownloadVector all_items;
  manager->GetAllDownloads(&all_items);

  // Create a Java array of all of the visible DownloadItems.
  JNIEnv* env = base::android::AttachCurrentThread();
  ScopedJavaLocalRef<jobject> j_download_item_list =
      Java_DownloadManagerService_createDownloadItemList(env, java_ref_);

  for (size_t i = 0; i < all_items.size(); i++) {
    download::DownloadItem* item = all_items[i];
    if (!ShouldShowDownloadItem(item))
      continue;

    ScopedJavaLocalRef<jobject> j_item =
        JNI_DownloadManagerService_CreateJavaDownloadItem(env, item);
    Java_DownloadManagerService_addDownloadItemToList(
        env, java_ref_, j_download_item_list, j_item);
  }

  Java_DownloadManagerService_onAllDownloadsRetrieved(
      env, java_ref_, j_download_item_list,
      profile_key->GetProfileKeyAndroid()->GetJavaObject());
}

void DownloadManagerService::CheckForExternallyRemovedDownloads(
    JNIEnv* env,
    const JavaParamRef<jobject>& obj,
    const JavaParamRef<jobject>& j_profile_key) {
  // Once the DownloadManager is initlaized, DownloadHistory will check for the
  // removal of history files. If the history query is not yet complete, ignore
  // requests to check for externally removed downloads.
  if (!is_manager_initialized_)
    return;

  content::DownloadManager* manager = GetDownloadManager(
      ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key));
  if (!manager)
    return;
  manager->CheckForHistoryFilesRemoval();
}

void DownloadManagerService::UpdateLastAccessTime(
    JNIEnv* env,
    const JavaParamRef<jobject>& obj,
    std::string& download_guid,
    const JavaParamRef<jobject>& j_profile_key) {
  ProfileKey* profile_key =
      ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key);
  download::DownloadItem* item = GetDownload(download_guid, profile_key);
  if (item)
    item->SetLastAccessTime(base::Time::Now());
}

void DownloadManagerService::CancelDownload(
    JNIEnv* env,
    jobject obj,
    std::string& download_guid,
    const JavaParamRef<jobject>& j_profile_key) {
  ProfileKey* profile_key =
      ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key);
  if (is_pending_downloads_loaded_ || profile_key->IsOffTheRecord())
    CancelDownloadInternal(download_guid, profile_key);
  else
    EnqueueDownloadAction(download_guid, CANCEL);
}

void DownloadManagerService::OnDownloadsInitialized(
    download::SimpleDownloadManagerCoordinator* coordinator,
    bool active_downloads_only) {
  if (active_downloads_only) {
    OnPendingDownloadsLoaded();
    return;
  }
  is_manager_initialized_ = true;
  OnPendingDownloadsLoaded();
  while (!profiles_with_pending_get_downloads_actions_.empty()) {
    ProfileKey* profile_key =
        profiles_with_pending_get_downloads_actions_.back();
    profiles_with_pending_get_downloads_actions_.pop_back();
    GetAllDownloadsInternal(profile_key);
  }
}

void DownloadManagerService::OnManagerGoingDown(
    download::SimpleDownloadManagerCoordinator* coordinator) {
  for (auto it = coordinators_.begin(); it != coordinators_.end(); it++) {
    if (it->second == coordinator) {
      coordinators_.erase(it->first);
      break;
    }
  }
}

void DownloadManagerService::OnDownloadCreated(
    download::SimpleDownloadManagerCoordinator* coordinator,
    download::DownloadItem* item) {
  if (item->IsTransient())
    return;

  JNIEnv* env = base::android::AttachCurrentThread();
  ScopedJavaLocalRef<jobject> j_item =
      JNI_DownloadManagerService_CreateJavaDownloadItem(env, item);
  Java_DownloadManagerService_onDownloadItemCreated(env, java_ref_, j_item);
}

void DownloadManagerService::OnDownloadUpdated(
    download::SimpleDownloadManagerCoordinator* coordinator,
    download::DownloadItem* item) {
  if (java_ref_.is_null())
    return;

  if (item->IsTemporary() || item->IsTransient())
    return;

  JNIEnv* env = base::android::AttachCurrentThread();
  ScopedJavaLocalRef<jobject> j_item =
      JNI_DownloadManagerService_CreateJavaDownloadItem(env, item);
  Java_DownloadManagerService_onDownloadItemUpdated(env, java_ref_, j_item);
}

void DownloadManagerService::OnDownloadRemoved(
    download::SimpleDownloadManagerCoordinator* coordinator,
    download::DownloadItem* item) {
  if (java_ref_.is_null() || item->IsTransient())
    return;

  const Profile* profile = Profile::FromBrowserContext(
      content::DownloadItemUtils::GetBrowserContext(item));

  JNIEnv* env = base::android::AttachCurrentThread();
  Java_DownloadManagerService_onDownloadItemRemoved(
      env, java_ref_, item->GetGuid(),
      profile->IsOffTheRecord()
          ? profile->GetOTRProfileID().ConvertToJavaOTRProfileID(env)
          : nullptr);
}

void DownloadManagerService::ResumeDownloadInternal(
    const std::string& download_guid,
    ProfileKey* profile_key) {
  download::DownloadItem* item = GetDownload(download_guid, profile_key);
  if (!item) {
    OnResumptionFailed(download_guid);
    return;
  }
  if (!item->CanResume()) {
    OnResumptionFailed(download_guid);
    return;
  }
  item->Resume(true /* user_resume */);
  if (resume_callback_for_testing_)
    std::move(resume_callback_for_testing_).Run(true);
}

void DownloadManagerService::CancelDownloadInternal(
    const std::string& download_guid,
    ProfileKey* profile_key) {
  download::DownloadItem* item = GetDownload(download_guid, profile_key);
  if (item) {
    // Remove the observer first to avoid item->Cancel() causing re-entrance
    // issue.
    item->RemoveObserver(DownloadControllerBase::Get());
    item->Cancel(true);
  }
}

void DownloadManagerService::PauseDownloadInternal(
    const std::string& download_guid,
    ProfileKey* profile_key) {
  download::DownloadItem* item = GetDownload(download_guid, profile_key);
  if (item)
    item->Pause();
}

void DownloadManagerService::RemoveDownloadInternal(
    const std::string& download_guid,
    ProfileKey* profile_key) {
  download::DownloadItem* item = GetDownload(download_guid, profile_key);
  if (item)
    item->Remove();
}

void DownloadManagerService::EnqueueDownloadAction(
    const std::string& download_guid,
    DownloadAction download_action) {
  auto iter = pending_actions_.find(download_guid);
  if (iter == pending_actions_.end()) {
    pending_actions_.insert(std::make_pair(download_guid, download_action));
    return;
  }
  switch (download_action) {
    case RESUME:
      if (iter->second == PAUSE) {
        iter->second = RESUME;
      }
      break;
    case PAUSE:
      if (iter->second == RESUME) {
        iter->second = PAUSE;
      }
      break;
    case CANCEL:
    case REMOVE:
      iter->second = download_action;
      break;
    default:
      NOTREACHED_IN_MIGRATION();
      break;
  }
}

void DownloadManagerService::OnResumptionFailed(
    const std::string& download_guid) {
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
      FROM_HERE,
      base::BindOnce(&DownloadManagerService::OnResumptionFailedInternal,
                     base::Unretained(this), download_guid));
}

void DownloadManagerService::OnResumptionFailedInternal(
    const std::string& download_guid) {
  if (!java_ref_.is_null()) {
    JNIEnv* env = base::android::AttachCurrentThread();
    Java_DownloadManagerService_onResumptionFailed(env, java_ref_,
                                                   download_guid);
  }
  if (resume_callback_for_testing_)
    std::move(resume_callback_for_testing_).Run(false);
}

download::DownloadItem* DownloadManagerService::GetDownload(
    const std::string& download_guid,
    ProfileKey* profile_key) {
  download::SimpleDownloadManagerCoordinator* coordinator =
      GetCoordinator(profile_key);
  return coordinator ? coordinator->GetDownloadByGuid(download_guid) : nullptr;
}

void DownloadManagerService::OnPendingDownloadsLoaded() {
  is_pending_downloads_loaded_ = true;

  auto result =
      base::ranges::find_if_not(coordinators_, &ProfileKey::IsOffTheRecord,
                                &Coordinators::value_type::first);
  CHECK(result != coordinators_.end())
      << "A non-OffTheRecord coordinator should exist when "
         "OnPendingDownloadsLoaded is triggered.";
  ProfileKey* profile_key = result->first;

  // Kick-off the auto-resumption handler.
  content::DownloadManager::DownloadVector all_items;
  GetCoordinator(profile_key)->GetAllDownloads(&all_items);

  if (!download::AutoResumptionHandler::Get())
    CreateAutoResumptionHandler();

  download::AutoResumptionHandler::Get()->SetResumableDownloads(all_items);

  for (auto iter = pending_actions_.begin(); iter != pending_actions_.end();
       ++iter) {
    DownloadAction action = iter->second;
    std::string download_guid = iter->first;
    switch (action) {
      case RESUME:
        ResumeDownloadInternal(download_guid, profile_key);
        break;
      case PAUSE:
        PauseDownloadInternal(download_guid, profile_key);
        break;
      case CANCEL:
        CancelDownloadInternal(download_guid, profile_key);
        break;
      default:
        NOTREACHED_IN_MIGRATION();
        break;
    }
  }
  pending_actions_.clear();
}

content::DownloadManager* DownloadManagerService::GetDownloadManager(
    ProfileKey* profile_key) {
  Profile* profile =
      IsReducedModeProfileKey(profile_key)
          ? ProfileManager::GetActiveUserProfile()
          : ProfileManager::GetProfileFromProfileKey(profile_key);
  content::DownloadManager* manager = profile->GetDownloadManager();
  ResetCoordinatorIfNeeded(profile_key);
  return manager;
}

void DownloadManagerService::ResetCoordinatorIfNeeded(ProfileKey* profile_key) {
  download::SimpleDownloadManagerCoordinator* coordinator =
      SimpleDownloadManagerCoordinatorFactory::GetForKey(profile_key);
  UpdateCoordinator(coordinator, profile_key);
}

void DownloadManagerService::UpdateCoordinator(
    download::SimpleDownloadManagerCoordinator* new_coordinator,
    ProfileKey* profile_key) {
  bool coordinator_exists = base::Contains(coordinators_, profile_key);
  if (!coordinator_exists || coordinators_[profile_key] != new_coordinator) {
    if (coordinator_exists)
      coordinators_[profile_key]->GetNotifier()->RemoveObserver(this);
    coordinators_[profile_key] = new_coordinator;
    new_coordinator->GetNotifier()->AddObserver(this);
  }
}

download::SimpleDownloadManagerCoordinator*
DownloadManagerService::GetCoordinator(ProfileKey* profile_key) {
  DCHECK(base::Contains(coordinators_, profile_key));
  return coordinators_[profile_key];
}

void DownloadManagerService::RenameDownload(
    JNIEnv* env,
    const JavaParamRef<jobject>& obj,
    std::string& download_guid,
    std::string& target_name,
    const JavaParamRef<jobject>& j_callback,
    const JavaParamRef<jobject>& j_profile_key) {
  ProfileKey* profile_key =
      ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key);
  download::DownloadItem* item = GetDownload(download_guid, profile_key);
  if (!item) {
    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(
            &RenameItemCallback,
            base::android::ScopedJavaGlobalRef<jobject>(env, j_callback),
            download::DownloadItem::DownloadRenameResult::FAILURE_UNAVAILABLE));

    return;
  }
  base::OnceCallback<void(download::DownloadItem::DownloadRenameResult)>
      callback = base::BindOnce(
          &RenameItemCallback,
          base::android::ScopedJavaGlobalRef<jobject>(env, j_callback));
  item->Rename(base::FilePath(target_name), std::move(callback));
}

void DownloadManagerService::CreateInterruptedDownloadForTest(
    JNIEnv* env,
    jobject obj,
    std::string& url,
    std::string& download_guid,
    std::string& target_path_str) {
  download::InProgressDownloadManager* in_progress_manager =
      DownloadManagerUtils::GetInProgressDownloadManager(
          ProfileKeyStartupAccessor::GetInstance()->profile_key());
  std::vector<GURL> url_chain;
  url_chain.emplace_back(url);
  base::FilePath target_path(target_path_str);
  in_progress_manager->AddInProgressDownloadForTest(
      std::make_unique<download::DownloadItemImpl>(
          in_progress_manager, download_guid, 1,
          target_path.AddExtension("crdownload"), target_path, url_chain,
          GURL(), "", GURL(), GURL(), url::Origin(), "", "", base::Time(),
          base::Time(), "", "", 0, -1, 0, "",
          download::DownloadItem::INTERRUPTED,
          download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
          download::DOWNLOAD_INTERRUPT_REASON_CRASH, false, false, false,
          base::Time(), false,
          std::vector<download::DownloadItem::ReceivedSlice>(),
          download::kInvalidRange, download::kInvalidRange, nullptr));
}

void DownloadManagerService::InitializeForProfile(ProfileKey* profile_key) {
  ResetCoordinatorIfNeeded(
      DownloadStartupUtils::EnsureDownloadSystemInitialized(profile_key));
}

// static
jboolean JNI_DownloadManagerService_IsSupportedMimeType(
    JNIEnv* env,
    std::string& mime_type) {
  return blink::IsSupportedMimeType(mime_type);
}

// static
jint JNI_DownloadManagerService_GetAutoResumptionLimit(JNIEnv* env) {
  std::string value = base::GetFieldTrialParamValueByFeature(
      chrome::android::kDownloadAutoResumptionThrottling,
      kAutoResumptionLimitParamName);
  int auto_resumption_limit;
  return base::StringToInt(value, &auto_resumption_limit)
             ? auto_resumption_limit
             : kDefaultAutoResumptionLimit;
}