1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/arc/arc_util.h"
6
7 #include <algorithm>
8 #include <cstdio>
9
10 #include "ash/public/cpp/app_types.h"
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/feature_list.h"
14 #include "base/optional.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "chromeos/constants/chromeos_switches.h"
17 #include "chromeos/dbus/concierge_client.h"
18 #include "chromeos/dbus/dbus_thread_manager.h"
19 #include "chromeos/dbus/debug_daemon/debug_daemon_client.h"
20 #include "chromeos/dbus/session_manager/session_manager_client.h"
21 #include "components/arc/arc_features.h"
22 #include "components/exo/shell_surface_util.h"
23 #include "components/user_manager/user_manager.h"
24 #include "ui/aura/client/aura_constants.h"
25 #include "ui/aura/window.h"
26 #include "ui/display/types/display_constants.h"
27
28 namespace arc {
29
30 namespace {
31
32 // This is for finch. See also crbug.com/633704 for details.
33 // TODO(hidehiko): More comments of the intention how this works, when
34 // we unify the commandline flags.
35 const base::Feature kEnableArcFeature{"EnableARC",
36 base::FEATURE_DISABLED_BY_DEFAULT};
37
38 // Possible values for --arc-availability flag.
39 constexpr char kAvailabilityNone[] = "none";
40 constexpr char kAvailabilityInstalled[] = "installed";
41 constexpr char kAvailabilityOfficiallySupported[] = "officially-supported";
42 constexpr char kAlwaysStartWithNoPlayStore[] =
43 "always-start-with-no-play-store";
44
SetArcCpuRestrictionCallback(login_manager::ContainerCpuRestrictionState state,bool success)45 void SetArcCpuRestrictionCallback(
46 login_manager::ContainerCpuRestrictionState state,
47 bool success) {
48 if (success)
49 return;
50 const char* message =
51 (state == login_manager::CONTAINER_CPU_RESTRICTION_BACKGROUND)
52 ? "unprioritize"
53 : "prioritize";
54 LOG(ERROR) << "Failed to " << message << " ARC";
55 }
56
OnSetArcVmCpuRestriction(base::Optional<vm_tools::concierge::SetVmCpuRestrictionResponse> response)57 void OnSetArcVmCpuRestriction(
58 base::Optional<vm_tools::concierge::SetVmCpuRestrictionResponse> response) {
59 if (!response) {
60 LOG(ERROR) << "Failed to call SetVmCpuRestriction";
61 return;
62 }
63 if (!response->success())
64 LOG(ERROR) << "SetVmCpuRestriction for ARCVM failed";
65 }
66
DoSetArcVmCpuRestriction(CpuRestrictionState cpu_restriction_state,bool concierge_started)67 void DoSetArcVmCpuRestriction(CpuRestrictionState cpu_restriction_state,
68 bool concierge_started) {
69 if (!concierge_started) {
70 LOG(ERROR) << "Concierge D-Bus service is not available";
71 return;
72 }
73
74 auto* client = chromeos::DBusThreadManager::Get()->GetConciergeClient();
75 if (!client) {
76 LOG(ERROR) << "ConciergeClient is not available";
77 return;
78 }
79
80 vm_tools::concierge::SetVmCpuRestrictionRequest request;
81 request.set_cpu_cgroup(vm_tools::concierge::CPU_CGROUP_ARCVM);
82 switch (cpu_restriction_state) {
83 case CpuRestrictionState::CPU_RESTRICTION_FOREGROUND:
84 request.set_cpu_restriction_state(
85 vm_tools::concierge::CPU_RESTRICTION_FOREGROUND);
86 break;
87 case CpuRestrictionState::CPU_RESTRICTION_BACKGROUND:
88 request.set_cpu_restriction_state(
89 vm_tools::concierge::CPU_RESTRICTION_BACKGROUND);
90 break;
91 }
92
93 client->SetVmCpuRestriction(request,
94 base::BindOnce(&OnSetArcVmCpuRestriction));
95 }
96
SetArcVmCpuRestriction(CpuRestrictionState cpu_restriction_state)97 void SetArcVmCpuRestriction(CpuRestrictionState cpu_restriction_state) {
98 auto* client = chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
99 if (!client) {
100 LOG(WARNING) << "DebugDaemonClient is not available";
101 return;
102 }
103 // TODO(wvk): Call StartConcierge() only when the service is not running.
104 client->StartConcierge(
105 base::BindOnce(&DoSetArcVmCpuRestriction, cpu_restriction_state));
106 }
107
SetArcContainerCpuRestriction(CpuRestrictionState cpu_restriction_state)108 void SetArcContainerCpuRestriction(CpuRestrictionState cpu_restriction_state) {
109 if (!chromeos::SessionManagerClient::Get()) {
110 LOG(WARNING) << "SessionManagerClient is not available";
111 return;
112 }
113
114 login_manager::ContainerCpuRestrictionState state;
115 switch (cpu_restriction_state) {
116 case CpuRestrictionState::CPU_RESTRICTION_FOREGROUND:
117 state = login_manager::CONTAINER_CPU_RESTRICTION_FOREGROUND;
118 break;
119 case CpuRestrictionState::CPU_RESTRICTION_BACKGROUND:
120 state = login_manager::CONTAINER_CPU_RESTRICTION_BACKGROUND;
121 break;
122 }
123 chromeos::SessionManagerClient::Get()->SetArcCpuRestriction(
124 state, base::BindOnce(SetArcCpuRestrictionCallback, state));
125 }
126
127 } // namespace
128
IsArcAvailable()129 bool IsArcAvailable() {
130 const auto* command_line = base::CommandLine::ForCurrentProcess();
131
132 if (command_line->HasSwitch(chromeos::switches::kArcAvailability)) {
133 const std::string value =
134 command_line->GetSwitchValueASCII(chromeos::switches::kArcAvailability);
135 DCHECK(value == kAvailabilityNone || value == kAvailabilityInstalled ||
136 value == kAvailabilityOfficiallySupported)
137 << "Unknown flag value: " << value;
138 return value == kAvailabilityOfficiallySupported ||
139 (value == kAvailabilityInstalled &&
140 base::FeatureList::IsEnabled(kEnableArcFeature));
141 }
142
143 // For transition, fallback to old flags.
144 // TODO(hidehiko): Remove this and clean up whole this function, when
145 // session_manager supports a new flag.
146 return command_line->HasSwitch(chromeos::switches::kEnableArc) ||
147 (command_line->HasSwitch(chromeos::switches::kArcAvailable) &&
148 base::FeatureList::IsEnabled(kEnableArcFeature));
149 }
150
IsArcVmEnabled()151 bool IsArcVmEnabled() {
152 return base::CommandLine::ForCurrentProcess()->HasSwitch(
153 chromeos::switches::kEnableArcVm);
154 }
155
ShouldArcAlwaysStart()156 bool ShouldArcAlwaysStart() {
157 const auto* command_line = base::CommandLine::ForCurrentProcess();
158 if (!command_line->HasSwitch(chromeos::switches::kArcStartMode))
159 return false;
160 return command_line->GetSwitchValueASCII(chromeos::switches::kArcStartMode) ==
161 kAlwaysStartWithNoPlayStore;
162 }
163
ShouldArcAlwaysStartWithNoPlayStore()164 bool ShouldArcAlwaysStartWithNoPlayStore() {
165 return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
166 chromeos::switches::kArcStartMode) == kAlwaysStartWithNoPlayStore;
167 }
168
ShouldShowOptInForTesting()169 bool ShouldShowOptInForTesting() {
170 return base::CommandLine::ForCurrentProcess()->HasSwitch(
171 chromeos::switches::kArcForceShowOptInUi);
172 }
173
SetArcAlwaysStartWithoutPlayStoreForTesting()174 void SetArcAlwaysStartWithoutPlayStoreForTesting() {
175 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
176 chromeos::switches::kArcStartMode, kAlwaysStartWithNoPlayStore);
177 }
178
IsArcKioskAvailable()179 bool IsArcKioskAvailable() {
180 const auto* command_line = base::CommandLine::ForCurrentProcess();
181
182 if (command_line->HasSwitch(chromeos::switches::kArcAvailability)) {
183 std::string value =
184 command_line->GetSwitchValueASCII(chromeos::switches::kArcAvailability);
185 if (value == kAvailabilityInstalled)
186 return true;
187 return IsArcAvailable();
188 }
189
190 // TODO(hidehiko): Remove this when session_manager supports the new flag.
191 if (command_line->HasSwitch(chromeos::switches::kArcAvailable))
192 return true;
193
194 // If not special kiosk device case, use general ARC check.
195 return IsArcAvailable();
196 }
197
SetArcAvailableCommandLineForTesting(base::CommandLine * command_line)198 void SetArcAvailableCommandLineForTesting(base::CommandLine* command_line) {
199 command_line->AppendSwitchASCII(chromeos::switches::kArcAvailability,
200 kAvailabilityOfficiallySupported);
201 }
202
IsArcKioskMode()203 bool IsArcKioskMode() {
204 return user_manager::UserManager::IsInitialized() &&
205 user_manager::UserManager::Get()->IsLoggedInAsArcKioskApp();
206 }
207
IsRobotOrOfflineDemoAccountMode()208 bool IsRobotOrOfflineDemoAccountMode() {
209 return user_manager::UserManager::IsInitialized() &&
210 (user_manager::UserManager::Get()->IsLoggedInAsArcKioskApp() ||
211 user_manager::UserManager::Get()->IsLoggedInAsPublicAccount());
212 }
213
IsArcAllowedForUser(const user_manager::User * user)214 bool IsArcAllowedForUser(const user_manager::User* user) {
215 if (!user) {
216 VLOG(1) << "No ARC for nullptr user.";
217 return false;
218 }
219
220 // ARC is only supported for the following cases:
221 // - Users have Gaia accounts;
222 // - Active directory users;
223 // - ARC kiosk session;
224 // - Public Session users;
225 // USER_TYPE_ARC_KIOSK_APP check is compatible with IsArcKioskMode()
226 // above because ARC kiosk user is always the primary/active user of a
227 // user session. The same for USER_TYPE_PUBLIC_ACCOUNT.
228 if (!user->HasGaiaAccount() && !user->IsActiveDirectoryUser() &&
229 user->GetType() != user_manager::USER_TYPE_ARC_KIOSK_APP &&
230 user->GetType() != user_manager::USER_TYPE_PUBLIC_ACCOUNT) {
231 VLOG(1) << "Users without GAIA or AD accounts, or not ARC kiosk apps are "
232 "not supported in ARC.";
233 return false;
234 }
235
236 return true;
237 }
238
IsArcOptInVerificationDisabled()239 bool IsArcOptInVerificationDisabled() {
240 return base::CommandLine::ForCurrentProcess()->HasSwitch(
241 chromeos::switches::kDisableArcOptInVerification);
242 }
243
IsArcAppWindow(const aura::Window * window)244 bool IsArcAppWindow(const aura::Window* window) {
245 if (!window)
246 return false;
247 return window->GetProperty(aura::client::kAppType) ==
248 static_cast<int>(ash::AppType::ARC_APP);
249 }
250
GetWindowTaskId(const aura::Window * window)251 int GetWindowTaskId(const aura::Window* window) {
252 if (!window)
253 return kNoTaskId;
254 const std::string* arc_app_id = exo::GetShellApplicationId(window);
255 if (!arc_app_id)
256 return kNoTaskId;
257 return GetTaskIdFromWindowAppId(*arc_app_id);
258 }
259
GetTaskIdFromWindowAppId(const std::string & app_id)260 int GetTaskIdFromWindowAppId(const std::string& app_id) {
261 int task_id;
262 if (std::sscanf(app_id.c_str(), "org.chromium.arc.%d", &task_id) != 1)
263 return kNoTaskId;
264 return task_id;
265 }
266
SetArcCpuRestriction(CpuRestrictionState cpu_restriction_state)267 void SetArcCpuRestriction(CpuRestrictionState cpu_restriction_state) {
268 // Ignore any calls to restrict the ARC container if the specified command
269 // line flag is set.
270 if (chromeos::switches::IsArcCpuRestrictionDisabled() &&
271 cpu_restriction_state == CpuRestrictionState::CPU_RESTRICTION_BACKGROUND)
272 return;
273
274 if (IsArcVmEnabled()) {
275 SetArcVmCpuRestriction(cpu_restriction_state);
276 } else {
277 SetArcContainerCpuRestriction(cpu_restriction_state);
278 }
279 }
280
IsArcForceCacheAppIcon()281 bool IsArcForceCacheAppIcon() {
282 return base::CommandLine::ForCurrentProcess()->HasSwitch(
283 chromeos::switches::kArcForceCacheAppIcons);
284 }
285
IsArcDataCleanupOnStartRequested()286 bool IsArcDataCleanupOnStartRequested() {
287 return base::CommandLine::ForCurrentProcess()->HasSwitch(
288 chromeos::switches::kArcDataCleanupOnStart);
289 }
290
IsArcAppSyncFlowDisabled()291 bool IsArcAppSyncFlowDisabled() {
292 return base::CommandLine::ForCurrentProcess()->HasSwitch(
293 chromeos::switches::kArcDisableAppSync);
294 }
295
IsArcLocaleSyncDisabled()296 bool IsArcLocaleSyncDisabled() {
297 return base::CommandLine::ForCurrentProcess()->HasSwitch(
298 chromeos::switches::kArcDisableLocaleSync);
299 }
300
IsArcPlayAutoInstallDisabled()301 bool IsArcPlayAutoInstallDisabled() {
302 return base::CommandLine::ForCurrentProcess()->HasSwitch(
303 chromeos::switches::kArcDisablePlayAutoInstall);
304 }
305
306 // static
GetLcdDensityForDeviceScaleFactor(float device_scale_factor)307 int32_t GetLcdDensityForDeviceScaleFactor(float device_scale_factor) {
308 const auto* command_line = base::CommandLine::ForCurrentProcess();
309 if (command_line->HasSwitch(chromeos::switches::kArcScale)) {
310 const std::string dpi_str =
311 command_line->GetSwitchValueASCII(chromeos::switches::kArcScale);
312 int dpi;
313 if (base::StringToInt(dpi_str, &dpi))
314 return dpi;
315 VLOG(1) << "Invalid Arc scale set. Using default.";
316 }
317 // TODO(b/131884992): Remove the logic to update default lcd density once
318 // per-display-density is supported.
319 constexpr float kEpsilon = 0.001;
320 if (std::abs(device_scale_factor - display::kDsf_2_252) < kEpsilon)
321 return 280;
322 if (std::abs(device_scale_factor - 1.6f) < kEpsilon)
323 return 213; // TVDPI
324 if (std::abs(device_scale_factor - display::kDsf_1_777) < kEpsilon)
325 return 240; // HDPI
326 if (std::abs(device_scale_factor - display::kDsf_2_666) < kEpsilon)
327 return 320; // XHDPI
328
329 constexpr float kChromeScaleToAndroidScaleRatio = 0.75f;
330 constexpr int32_t kDefaultDensityDpi = 160;
331 return static_cast<int32_t>(
332 std::max(1.0f, device_scale_factor * kChromeScaleToAndroidScaleRatio) *
333 kDefaultDensityDpi);
334 }
335
336 } // namespace arc
337