1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
// 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/task_manager/providers/arc/arc_process_task.h"
#include <utility>
#include "base/functional/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 "chromeos/ash/experiences/arc/arc_util.h"
#include "chromeos/ash/experiences/arc/intent_helper/arc_intent_helper_bridge.h"
#include "chromeos/ash/experiences/arc/mojom/process.mojom.h"
#include "chromeos/ash/experiences/arc/session/arc_bridge_service.h"
#include "chromeos/ash/experiences/arc/session/arc_service_manager.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_host.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/image/image.h"
namespace task_manager {
namespace {
// |arc_process_.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 |arc_process_.packages()| list, just use the first item
// in the list. In some case, |arc_process_.packages()| is empty, 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::string FirstPackage(const std::vector<std::string>& packages) {
return packages.empty() ? std::string() : packages[0];
}
std::u16string MakeTitle(const arc::ArcProcess& arc_process) {
int name_template = IDS_TASK_MANAGER_ARC_PREFIX;
switch (arc_process.process_state()) {
case arc::mojom::ProcessState::PERSISTENT:
case arc::mojom::ProcessState::PERSISTENT_UI:
name_template = IDS_TASK_MANAGER_ARC_SYSTEM;
break;
case arc::mojom::ProcessState::FOREGROUND_SERVICE:
case arc::mojom::ProcessState::BOUND_FOREGROUND_SERVICE:
case arc::mojom::ProcessState::IMPORTANT_FOREGROUND:
case arc::mojom::ProcessState::IMPORTANT_BACKGROUND:
case arc::mojom::ProcessState::TRANSIENT_BACKGROUND:
case arc::mojom::ProcessState::SERVICE:
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;
}
std::u16string title = l10n_util::GetStringFUTF16(
name_template, base::UTF8ToUTF16(arc_process.process_name()));
base::i18n::AdjustStringForLocaleDirection(&title);
return title;
}
// An activity name for retrieving the package's default icon without
// specifying an activity name.
constexpr char kEmptyActivityName[] = "";
} // namespace
ArcProcessTask::ArcProcessTask(arc::ArcProcess arc_process)
: Task(MakeTitle(arc_process),
nullptr /* icon */,
arc_process.pid()),
arc_process_(std::move(arc_process)) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
StartIconLoading();
}
void ArcProcessTask::StartIconLoading() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// TaskManager is not tied to BrowserContext. Thus, we just use the
// BrowserContext which is tied to ARC.
auto* arc_service_manager = arc::ArcServiceManager::Get();
auto* intent_helper_bridge = arc::ArcIntentHelperBridge::GetForBrowserContext(
arc_service_manager->browser_context());
arc::ArcIntentHelperBridge::GetResult result =
arc::ArcIntentHelperBridge::GetResult::FAILED_ARC_NOT_READY;
if (intent_helper_bridge) {
std::vector<arc::ArcIntentHelperBridge::ActivityName> activities = {
{FirstPackage(arc_process_.packages()), kEmptyActivityName}};
result = intent_helper_bridge->GetActivityIcons(
activities, base::BindOnce(&ArcProcessTask::OnIconLoaded,
weak_ptr_factory_.GetWeakPtr()));
}
if (result == arc::ArcIntentHelperBridge::GetResult::FAILED_ARC_NOT_READY) {
// Need to retry loading the icon.
arc_service_manager->arc_bridge_service()->intent_helper()->AddObserver(
this);
}
}
ArcProcessTask::~ArcProcessTask() {
auto* service_manager = arc::ArcServiceManager::Get();
// This destructor can also be called when TaskManagerImpl is destructed.
// Since TaskManagerImpl is a LAZY_INSTANCE, arc::ArcServiceManager may have
// already been destructed. In that case, arc_bridge_service() has also been
// destructed, and it is safe to just return.
if (!service_manager)
return;
service_manager->arc_bridge_service()->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 !arc_process_.IsPersistent();
}
bool ArcProcessTask::IsRunningInVM() const {
return arc::IsArcVmEnabled();
}
bool ArcProcessTask::Kill() {
auto* process_instance = ARC_GET_INSTANCE_FOR_METHOD(
arc::ArcServiceManager::Get()->arc_bridge_service()->process(),
KillProcess);
if (!process_instance)
return false;
process_instance->KillProcess(arc_process_.nspid(),
"Killed manually from Task Manager");
return true;
}
void ArcProcessTask::OnConnectionReady() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
VLOG(2) << "intent_helper instance is ready. Fetching the icon for "
<< FirstPackage(arc_process_.packages());
arc::ArcServiceManager::Get()
->arc_bridge_service()
->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::ArcIntentHelperBridge::GetActivityIcon() may fail again.
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&ArcProcessTask::StartIconLoading,
weak_ptr_factory_.GetWeakPtr()));
}
void ArcProcessTask::SetProcessState(arc::mojom::ProcessState process_state) {
arc_process_.set_process_state(process_state);
}
void ArcProcessTask::OnIconLoaded(
std::unique_ptr<arc::ArcIntentHelperBridge::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
|