blob: 1f0b4fee445bb8451ab42c4db9770c5464ffb7e4 [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/task_manager/providers/arc/arc_process_task.h"
#include "base/bind.h"
#include "base/i18n/rtl.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/grit/generated_resources.h"
#include "components/arc/arc_service_manager.h"
#include "components/arc/common/process.mojom.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/child_process_host.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/image/image.h"
namespace task_manager {
namespace {
constexpr uint32_t kKillProcessMinInstanceVersion = 1;
base::string16 MakeTitle(const std::string& process_name,
arc::mojom::ProcessState process_state) {
int name_template = IDS_TASK_MANAGER_ARC_PREFIX;
switch (process_state) {
case arc::mojom::ProcessState::PERSISTENT:
case arc::mojom::ProcessState::PERSISTENT_UI:
case arc::mojom::ProcessState::TOP:
name_template = IDS_TASK_MANAGER_ARC_SYSTEM;
break;
case arc::mojom::ProcessState::BOUND_FOREGROUND_SERVICE:
case arc::mojom::ProcessState::FOREGROUND_SERVICE:
case arc::mojom::ProcessState::SERVICE:
case arc::mojom::ProcessState::IMPORTANT_FOREGROUND:
case arc::mojom::ProcessState::IMPORTANT_BACKGROUND:
name_template = IDS_TASK_MANAGER_ARC_PREFIX_BACKGROUND_SERVICE;
break;
case arc::mojom::ProcessState::RECEIVER:
name_template = IDS_TASK_MANAGER_ARC_PREFIX_RECEIVER;
break;
default:
break;
}
base::string16 title = l10n_util::GetStringFUTF16(
name_template, base::UTF8ToUTF16(process_name));
base::i18n::AdjustStringForLocaleDirection(&title);
return title;
}
scoped_refptr<arc::ActivityIconLoader> GetIconLoader() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
arc::ArcServiceManager* arc_service_manager = arc::ArcServiceManager::Get();
if (!arc_service_manager)
return nullptr;
return arc_service_manager->icon_loader();
}
// An activity name for retrieving the package's default icon without
// specifying an activity name.
constexpr char kEmptyActivityName[] = "";
} // namespace
ArcProcessTask::ArcProcessTask(base::ProcessId pid,
base::ProcessId nspid,
const std::string& process_name,
arc::mojom::ProcessState process_state,
const std::vector<std::string>& packages)
: Task(MakeTitle(process_name, process_state),
process_name,
nullptr /* icon */,
pid),
nspid_(nspid),
process_name_(process_name),
process_state_(process_state),
// |packages| contains an alphabetically-sorted list of package names the
// process has. Since the Task class can hold only one icon per process,
// and there is no reliable way to pick the most important process from
// the |packages| list, just use the first item in the list.
package_name_(packages.empty() ? "" : packages.at(0)),
weak_ptr_factory_(this) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
StartIconLoading();
}
void ArcProcessTask::StartIconLoading() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
scoped_refptr<arc::ActivityIconLoader> icon_loader = GetIconLoader();
arc::ActivityIconLoader::GetResult result =
arc::ActivityIconLoader::GetResult::FAILED_ARC_NOT_READY;
if (icon_loader) {
// In some case, the package_name_ does not exists, it would be expected to
// get default process icon. For example, daemon processes in android
// container such like surfaceflinger, debuggerd or installd. Each of them
// would be shown on task manager but does not have a package name.
std::vector<arc::ActivityIconLoader::ActivityName> activities = {
{package_name_, kEmptyActivityName}};
result = icon_loader->GetActivityIcons(
activities, base::Bind(&ArcProcessTask::OnIconLoaded,
weak_ptr_factory_.GetWeakPtr()));
}
if (result == arc::ActivityIconLoader::GetResult::FAILED_ARC_NOT_READY) {
// Need to retry loading the icon.
arc::ArcBridgeService::Get()->intent_helper()->AddObserver(this);
}
}
ArcProcessTask::~ArcProcessTask() {
arc::ArcBridgeService::Get()->intent_helper()->RemoveObserver(this);
}
Task::Type ArcProcessTask::GetType() const {
return Task::ARC;
}
int ArcProcessTask::GetChildProcessUniqueID() const {
// ARC process is not a child process of the browser.
return content::ChildProcessHost::kInvalidUniqueID;
}
bool ArcProcessTask::IsKillable() {
// Do not kill persistent processes.
return process_state_ > arc::mojom::ProcessState::PERSISTENT_UI;
}
void ArcProcessTask::Kill() {
auto* process_instance =
arc::ArcBridgeService::Get()->process()->GetInstanceForMethod(
"KillProcess", kKillProcessMinInstanceVersion);
if (!process_instance)
return;
process_instance->KillProcess(nspid_, "Killed manually from Task Manager");
}
void ArcProcessTask::OnInstanceReady() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
VLOG(2) << "intent_helper instance is ready. Fetching the icon for "
<< package_name_;
arc::ArcBridgeService::Get()->intent_helper()->RemoveObserver(this);
// Instead of calling into StartIconLoading() directly, return to the main
// loop first to make sure other ArcBridgeService observers are notified.
// Otherwise, arc::ActivityIconLoader::GetActivityIcon() may fail again.
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&ArcProcessTask::StartIconLoading,
weak_ptr_factory_.GetWeakPtr()));
}
void ArcProcessTask::SetProcessState(arc::mojom::ProcessState process_state) {
process_state_ = process_state;
}
void ArcProcessTask::OnIconLoaded(
std::unique_ptr<arc::ActivityIconLoader::ActivityToIconsMap> icons) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
for (const auto& kv : *icons) {
const gfx::Image& icon = kv.second.icon16;
if (icon.IsEmpty())
continue;
set_icon(*icon.ToImageSkia());
break; // Since the parent class can hold only one icon, break here.
}
}
} // namespace task_manager