blob: cf79ed0d854e27e9d749fab472cae17872cf7067 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// 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 "base/android/callback_android.h"
#include "base/android/jni_string.h"
#include "base/android/path_utils.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/metrics/field_trial_params.h"
#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "chrome/android/chrome_jni_headers/DownloadItem_jni.h"
#include "chrome/android/chrome_jni_headers/DownloadManagerService_jni.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/jni_headers/DownloadInfo_jni.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/cached_feature_flags.h"
#include "chrome/browser/flags/android/chrome_feature_list.h"
#include "chrome/browser/profiles/profile_android.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/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 "third_party/blink/public/common/mime_util/mime_util.h"
#include "url/origin.h"
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF16ToJavaString;
using base::android::ConvertUTF8ToJavaString;
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
using offline_items_collection::android::OfflineItemBridge;
using DownloadSchedule = download::DownloadSchedule;
using OfflineItemSchedule = offline_items_collection::OfflineItemSchedule;
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().ToJavaTime(), item->GetEndTime().ToJavaTime(),
item->GetFileExternallyRemoved());
}
void RenameItemCallback(
const base::android::ScopedJavaGlobalRef<jobject> j_callback,
download::DownloadItem::DownloadRenameResult result) {
base::android::RunIntCallbackAndroid(
j_callback,
static_cast<int>(
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 =
chrome::android::IsJavaDrivenFeatureEnabled(
download::features::kDownloadAutoResumptionNative);
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);
std::string original_url = item->GetOriginalUrl().SchemeIs(url::kDataScheme)
? std::string()
: item->GetOriginalUrl().spec();
content::BrowserContext* browser_context =
content::DownloadItemUtils::GetBrowserContext(item);
base::Optional<OfflineItemSchedule> offline_item_schedule;
auto download_schedule = item->GetDownloadSchedule();
if (download_schedule.has_value()) {
offline_item_schedule = base::make_optional<OfflineItemSchedule>(
download_schedule->only_on_wifi(), download_schedule->start_time());
}
auto j_offline_item_schedule =
OfflineItemBridge::CreateOfflineItemSchedule(env, offline_item_schedule);
return Java_DownloadInfo_createDownloadInfo(
env, ConvertUTF8ToJavaString(env, item->GetGuid()),
ConvertUTF8ToJavaString(env, item->GetFileNameToReportUser().value()),
ConvertUTF8ToJavaString(env, item->GetTargetFilePath().value()),
ConvertUTF8ToJavaString(env, item->GetTabUrl().spec()),
ConvertUTF8ToJavaString(env, item->GetMimeType()),
item->GetReceivedBytes(), item->GetTotalBytes(),
browser_context ? browser_context->IsOffTheRecord() : false,
item->GetState(), item->PercentComplete(), item->IsPaused(),
DownloadUtils::IsDownloadUserInitiated(item), item->CanResume(),
item->IsParallelDownload(), ConvertUTF8ToJavaString(env, original_url),
ConvertUTF8ToJavaString(env, item->GetReferrerUrl().spec()),
time_remaining_known ? time_delta.InMilliseconds()
: kUnknownRemainingTime,
item->GetLastAccessTime().ToJavaTime(), item->IsDangerous(),
static_cast<int>(
OfflineItemUtils::ConvertDownloadInterruptReasonToFailState(
item->GetLastReason())),
j_offline_item_schedule);
}
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::DownloadActionParams::DownloadActionParams(
DownloadAction download_action)
: action(download_action), has_user_gesture(false) {}
DownloadManagerService::DownloadActionParams::DownloadActionParams(
DownloadAction download_action,
bool user_gesture)
: action(download_action), has_user_gesture(user_gesture) {}
DownloadManagerService::DownloadActionParams::DownloadActionParams(
const DownloadActionParams& other)
: action(other.action), has_user_gesture(other.has_user_gesture) {}
DownloadManagerService::DownloadManagerService()
: is_manager_initialized_(false),
is_pending_downloads_loaded_(false),
original_coordinator_(nullptr),
off_the_record_coordinator_(nullptr) {}
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,
const JavaParamRef<jobject>& j_profile) {
OnProfileAdded(ProfileAndroid::FromProfileAndroid(j_profile));
}
void DownloadManagerService::OnProfileAdded(Profile* profile) {
InitializeForProfile(profile->GetProfileKey());
observed_profiles_.Add(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,
const JavaParamRef<jstring>& jdownload_guid,
const JavaParamRef<jobject>& j_profile_key,
jint source) {
if (!is_manager_initialized_)
return;
std::string download_guid = ConvertJavaStringToUTF8(env, jdownload_guid);
download::DownloadItem* item = GetDownload(
download_guid, ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key));
if (!item)
return;
OpenDownload(item, source);
}
void DownloadManagerService::ResumeDownload(
JNIEnv* env,
jobject obj,
const JavaParamRef<jstring>& jdownload_guid,
const JavaParamRef<jobject>& j_profile_key,
bool has_user_gesture) {
std::string download_guid = ConvertJavaStringToUTF8(env, jdownload_guid);
ProfileKey* profile_key =
ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key);
if (is_pending_downloads_loaded_ || profile_key->IsOffTheRecord()) {
ResumeDownloadInternal(download_guid, profile_key, has_user_gesture);
} else {
EnqueueDownloadAction(download_guid,
DownloadActionParams(RESUME, has_user_gesture));
}
}
void DownloadManagerService::RetryDownload(
JNIEnv* env,
jobject obj,
const JavaParamRef<jstring>& jdownload_guid,
const JavaParamRef<jobject>& j_profile_key,
bool has_user_gesture) {
std::string download_guid = ConvertJavaStringToUTF8(env, jdownload_guid);
ProfileKey* profile_key =
ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key);
if (is_pending_downloads_loaded_ || profile_key->IsOffTheRecord())
RetryDownloadInternal(download_guid, profile_key, has_user_gesture);
else
EnqueueDownloadAction(download_guid, DownloadActionParams(RETRY));
}
void DownloadManagerService::PauseDownload(
JNIEnv* env,
jobject obj,
const JavaParamRef<jstring>& jdownload_guid,
const JavaParamRef<jobject>& j_profile_key) {
std::string download_guid = ConvertJavaStringToUTF8(env, jdownload_guid);
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, DownloadActionParams(PAUSE));
}
void DownloadManagerService::RemoveDownload(
JNIEnv* env,
jobject obj,
const JavaParamRef<jstring>& jdownload_guid,
const JavaParamRef<jobject>& j_profile_key) {
std::string download_guid = ConvertJavaStringToUTF8(env, jdownload_guid);
ProfileKey* profile_key =
ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key);
if (is_manager_initialized_ || profile_key->IsOffTheRecord())
RemoveDownloadInternal(download_guid, profile_key);
else
EnqueueDownloadAction(download_guid, DownloadActionParams(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,
ProfileKeyAndroid(profile_key).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,
const JavaParamRef<jstring>& jdownload_guid,
const JavaParamRef<jobject>& j_profile_key) {
std::string download_guid = ConvertJavaStringToUTF8(env, jdownload_guid);
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,
const JavaParamRef<jstring>& jdownload_guid,
const JavaParamRef<jobject>& j_profile_key) {
std::string download_guid = ConvertJavaStringToUTF8(env, jdownload_guid);
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, DownloadActionParams(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) {
if (original_coordinator_ == coordinator)
original_coordinator_ = nullptr;
else if (off_the_record_coordinator_ == coordinator)
off_the_record_coordinator_ = nullptr;
}
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;
JNIEnv* env = base::android::AttachCurrentThread();
Java_DownloadManagerService_onDownloadItemRemoved(
env, java_ref_, ConvertUTF8ToJavaString(env, item->GetGuid()),
content::DownloadItemUtils::GetBrowserContext(item)->IsOffTheRecord());
}
void DownloadManagerService::ResumeDownloadInternal(
const std::string& download_guid,
ProfileKey* profile_key,
bool has_user_gesture) {
download::DownloadItem* item = GetDownload(download_guid, profile_key);
if (!item) {
OnResumptionFailed(download_guid);
return;
}
if (!item->CanResume()) {
OnResumptionFailed(download_guid);
return;
}
DownloadControllerBase::Get()->AboutToResumeDownload(item);
item->Resume(has_user_gesture);
if (!resume_callback_for_testing_.is_null())
resume_callback_for_testing_.Run(true);
}
void DownloadManagerService::RetryDownloadInternal(
const std::string& download_guid,
ProfileKey* profile_key,
bool has_user_gesture) {
content::DownloadManager* manager = GetDownloadManager(profile_key);
if (!manager)
return;
download::DownloadItem* item = manager->GetDownloadByGuid(download_guid);
if (!item)
return;
// Try to resume first.
if (item->CanResume()) {
item->Resume(has_user_gesture);
return;
}
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("download_manager_service_retry", R"(
semantics {
sender: "DownloadManagerService"
description:
"Retry a download by creating new network request."
trigger:
"User retries a download."
data: "None."
destination: WEBSITE
}
policy {
cookies_allowed: YES
cookies_store: "user"
setting:
"This feature cannot be disabled in settings, but it is activated "
"by direct user action."
chrome_policy {
DownloadRestrictions {
DownloadRestrictions: 3
}
}
})");
auto download_url_params = std::make_unique<download::DownloadUrlParameters>(
item->GetURL(), traffic_annotation);
// Retry allows redirect.
download_url_params->set_cross_origin_redirects(
network::mojom::RedirectMode::kFollow);
// Retry is triggered through user gesture, and don't have renderer
// associated, content initiated has to be false to avoid download being
// blocked.
download_url_params->set_content_initiated(false);
// TODO(xingliu): See if we need to persist the referrer policy. Never clear
// referrer potentially may result in delivering unexpected referrer to web
// servers.
download_url_params->set_referrer_policy(
net::URLRequest::NEVER_CLEAR_REFERRER);
download_url_params->set_referrer(item->GetReferrerUrl());
download_url_params->set_download_source(download::DownloadSource::RETRY);
// Creates a new download.
manager->DownloadUrl(std::move(download_url_params));
// Removes the current download.
item->Remove();
}
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,
const DownloadActionParams& params) {
auto iter = pending_actions_.find(download_guid);
if (iter == pending_actions_.end()) {
pending_actions_.insert(std::make_pair(download_guid, params));
return;
}
switch (params.action) {
case RESUME:
if (iter->second.action == PAUSE)
iter->second = params;
break;
case PAUSE:
if (iter->second.action == RESUME)
iter->second = params;
break;
case CANCEL:
iter->second = params;
break;
case REMOVE:
iter->second = params;
break;
default:
NOTREACHED();
break;
}
}
void DownloadManagerService::OnResumptionFailed(
const std::string& download_guid) {
base::ThreadTaskRunnerHandle::Get()->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_, ConvertUTF8ToJavaString(env, download_guid));
}
if (!resume_callback_for_testing_.is_null())
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;
// Kick-off the auto-resumption handler.
content::DownloadManager::DownloadVector all_items;
original_coordinator_->GetAllDownloads(&all_items);
if (!download::AutoResumptionHandler::Get())
CreateAutoResumptionHandler();
download::AutoResumptionHandler::Get()->SetResumableDownloads(all_items);
ProfileKey* profile_key =
use_startup_accessor_profile_key_for_testing_
? ProfileKeyStartupAccessor::GetInstance()->profile_key()
: ProfileManager::GetActiveUserProfile()
->GetOriginalProfile()
->GetProfileKey();
for (auto iter = pending_actions_.begin(); iter != pending_actions_.end();
++iter) {
DownloadActionParams params = iter->second;
std::string download_guid = iter->first;
switch (params.action) {
case RESUME:
ResumeDownloadInternal(download_guid, profile_key,
params.has_user_gesture);
break;
case PAUSE:
PauseDownloadInternal(download_guid, profile_key);
break;
case CANCEL:
CancelDownloadInternal(download_guid, profile_key);
break;
default:
NOTREACHED();
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 =
content::BrowserContext::GetDownloadManager(profile);
ResetCoordinatorIfNeeded(profile_key);
return manager;
}
void DownloadManagerService::ResetCoordinatorIfNeeded(ProfileKey* profile_key) {
download::SimpleDownloadManagerCoordinator* coordinator =
SimpleDownloadManagerCoordinatorFactory::GetForKey(profile_key);
UpdateCoordinator(coordinator, profile_key->IsOffTheRecord());
}
void DownloadManagerService::UpdateCoordinator(
download::SimpleDownloadManagerCoordinator* new_coordinator,
bool is_off_the_record) {
// TODO(https://crbug.com/1099577): Update to have separate coordinators per
// OTR profile.
auto*& coordinator =
is_off_the_record ? off_the_record_coordinator_ : original_coordinator_;
if (!coordinator || coordinator != new_coordinator) {
if (coordinator)
coordinator->GetNotifier()->RemoveObserver(this);
coordinator = new_coordinator;
coordinator->GetNotifier()->AddObserver(this);
}
}
download::SimpleDownloadManagerCoordinator*
DownloadManagerService::GetCoordinator(ProfileKey* profile_key) {
// TODO(https://crbug.com/1099577): Update to have separate coordinators per
// OTR profile.
bool use_original = use_startup_accessor_profile_key_for_testing_ ||
!profile_key->IsOffTheRecord();
return use_original ? original_coordinator_ : off_the_record_coordinator_;
}
void DownloadManagerService::RenameDownload(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jstring>& id,
const JavaParamRef<jstring>& name,
const JavaParamRef<jobject>& j_callback,
const JavaParamRef<jobject>& j_profile_key) {
std::string download_guid = ConvertJavaStringToUTF8(id);
ProfileKey* profile_key =
ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key);
download::DownloadItem* item = GetDownload(download_guid, profile_key);
if (!item) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(
&RenameItemCallback,
base::android::ScopedJavaGlobalRef<jobject>(env, j_callback),
download::DownloadItem::DownloadRenameResult::FAILURE_UNAVAILABLE));
return;
}
std::string target_name = ConvertJavaStringToUTF8(name);
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::ChangeSchedule(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jstring>& id,
jboolean only_on_wifi,
jlong start_time,
const JavaParamRef<jobject>& j_profile_key) {
std::string download_guid = ConvertJavaStringToUTF8(id);
download::DownloadItem* item = GetDownload(
download_guid, ProfileKeyAndroid::FromProfileKeyAndroid(j_profile_key));
if (!item)
return;
base::Optional<DownloadSchedule> download_schedule;
if (only_on_wifi) {
download_schedule = base::make_optional<DownloadSchedule>(
true /*only_on_wifi*/, base::nullopt);
} else if (start_time > 0) {
download_schedule = base::make_optional<DownloadSchedule>(
false /*only_on_wifi*/, base::Time::FromJavaTime(start_time));
}
item->OnDownloadScheduleChanged(std::move(download_schedule));
}
void DownloadManagerService::CreateInterruptedDownloadForTest(
JNIEnv* env,
jobject obj,
const JavaParamRef<jstring>& jurl,
const JavaParamRef<jstring>& jdownload_guid,
const JavaParamRef<jstring>& jtarget_path) {
download::InProgressDownloadManager* in_progress_manager =
DownloadManagerUtils::GetInProgressDownloadManager(
ProfileKeyStartupAccessor::GetInstance()->profile_key());
UseStartupProfileKeyForTesting();
std::vector<GURL> url_chain;
url_chain.emplace_back(ConvertJavaStringToUTF8(env, jurl));
base::FilePath target_path(ConvertJavaStringToUTF8(env, jtarget_path));
in_progress_manager->AddInProgressDownloadForTest(
std::make_unique<download::DownloadItemImpl>(
in_progress_manager, ConvertJavaStringToUTF8(env, jdownload_guid), 1,
target_path.AddExtension("crdownload"), target_path, url_chain,
GURL(), 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>(),
base::nullopt /*download_schedule*/, nullptr));
}
void DownloadManagerService::InitializeForProfile(ProfileKey* profile_key) {
ResetCoordinatorIfNeeded(
DownloadStartupUtils::EnsureDownloadSystemInitialized(profile_key));
}
// static
jboolean JNI_DownloadManagerService_IsSupportedMimeType(
JNIEnv* env,
const JavaParamRef<jstring>& jmime_type) {
std::string mime_type = ConvertJavaStringToUTF8(env, jmime_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;
}