arc_util.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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. #include "ash/components/arc/arc_util.h"
  5. #include <algorithm>
  6. #include <cstdio>
  7. #include "ash/components/arc/arc_features.h"
  8. #include "ash/constants/app_types.h"
  9. #include "ash/constants/ash_switches.h"
  10. #include "base/bind.h"
  11. #include "base/command_line.h"
  12. #include "base/feature_list.h"
  13. #include "base/logging.h"
  14. #include "base/process/launch.h"
  15. #include "base/process/process_metrics.h"
  16. #include "base/strings/string_number_conversions.h"
  17. #include "base/strings/string_util.h"
  18. #include "chromeos/ash/components/dbus/debug_daemon/debug_daemon_client.h"
  19. #include "chromeos/ash/components/dbus/upstart/upstart_client.h"
  20. #include "components/exo/shell_surface_util.h"
  21. #include "components/user_manager/user_manager.h"
  22. #include "third_party/abseil-cpp/absl/types/optional.h"
  23. #include "ui/aura/client/aura_constants.h"
  24. #include "ui/aura/window.h"
  25. #include "ui/display/types/display_constants.h"
  26. namespace arc {
  27. namespace {
  28. // This is for finch. See also crbug.com/633704 for details.
  29. // TODO(hidehiko): More comments of the intention how this works, when
  30. // we unify the commandline flags.
  31. const base::Feature kEnableArcFeature{"EnableARC",
  32. base::FEATURE_DISABLED_BY_DEFAULT};
  33. // Possible values for --arc-availability flag.
  34. constexpr char kAvailabilityNone[] = "none";
  35. constexpr char kAvailabilityInstalled[] = "installed";
  36. constexpr char kAvailabilityOfficiallySupported[] = "officially-supported";
  37. constexpr char kAlwaysStartWithNoPlayStore[] =
  38. "always-start-with-no-play-store";
  39. constexpr char kManualStart[] = "manual";
  40. constexpr const char kCrosSystemPath[] = "/usr/bin/crossystem";
  41. // ArcVmUreadaheadMode param value strings.
  42. constexpr char kGenerate[] = "generate";
  43. constexpr char kDisabled[] = "disabled";
  44. // Do not run ureadahead in vm for devices with less than 8GB due to memory
  45. // pressure issues since system will likely drop caches in this case.
  46. // The value should match platform2/arc/vm/scripts/init/arcvm-ureadahead.conf
  47. // in Chrome OS.
  48. constexpr int kReadaheadTotalMinMemoryInKb = 7500000;
  49. // Decodes a job name that may have "_2d" e.g. |kArcCreateDataJobName|
  50. // and returns a decoded string.
  51. std::string DecodeJobName(const std::string& raw_job_name) {
  52. constexpr const char* kFind = "_2d";
  53. std::string decoded(raw_job_name);
  54. base::ReplaceSubstringsAfterOffset(&decoded, 0, kFind, "-");
  55. return decoded;
  56. }
  57. // Called when the Upstart operation started in ConfigureUpstartJobs is
  58. // done. Handles the fatal error (if any) and then starts the next job.
  59. void OnConfigureUpstartJobs(std::deque<JobDesc> jobs,
  60. chromeos::VoidDBusMethodCallback callback,
  61. bool result) {
  62. const std::string job_name = DecodeJobName(jobs.front().job_name);
  63. const bool is_start = (jobs.front().operation == UpstartOperation::JOB_START);
  64. if (!result && is_start) {
  65. LOG(ERROR) << "Failed to start " << job_name;
  66. // TODO(yusukes): Record UMA for this case.
  67. std::move(callback).Run(false);
  68. return;
  69. }
  70. VLOG(1) << job_name
  71. << (is_start ? " started" : (result ? " stopped " : " not running?"));
  72. jobs.pop_front();
  73. ConfigureUpstartJobs(std::move(jobs), std::move(callback));
  74. }
  75. } // namespace
  76. bool IsArcAvailable() {
  77. const auto* command_line = base::CommandLine::ForCurrentProcess();
  78. if (command_line->HasSwitch(ash::switches::kArcAvailability)) {
  79. const std::string value =
  80. command_line->GetSwitchValueASCII(ash::switches::kArcAvailability);
  81. DCHECK(value == kAvailabilityNone || value == kAvailabilityInstalled ||
  82. value == kAvailabilityOfficiallySupported)
  83. << "Unknown flag value: " << value;
  84. return value == kAvailabilityOfficiallySupported ||
  85. (value == kAvailabilityInstalled &&
  86. base::FeatureList::IsEnabled(kEnableArcFeature));
  87. }
  88. // For transition, fallback to old flags.
  89. // TODO(hidehiko): Remove this and clean up whole this function, when
  90. // session_manager supports a new flag.
  91. return command_line->HasSwitch(ash::switches::kEnableArc) ||
  92. (command_line->HasSwitch(ash::switches::kArcAvailable) &&
  93. base::FeatureList::IsEnabled(kEnableArcFeature));
  94. }
  95. bool IsArcVmEnabled() {
  96. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  97. ash::switches::kEnableArcVm);
  98. }
  99. bool IsArcVmRtVcpuEnabled(uint32_t cpus) {
  100. // TODO(kansho): remove switch after tast test use Finch instead.
  101. if (base::CommandLine::ForCurrentProcess()->HasSwitch(
  102. ash::switches::kEnableArcVmRtVcpu)) {
  103. return true;
  104. }
  105. if (cpus == 2 && base::FeatureList::IsEnabled(kRtVcpuDualCore))
  106. return true;
  107. if (cpus > 2 && base::FeatureList::IsEnabled(kRtVcpuQuadCore))
  108. return true;
  109. return false;
  110. }
  111. bool IsArcVmUseHugePages() {
  112. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  113. ash::switches::kArcVmUseHugePages);
  114. }
  115. bool IsArcVmDevConfIgnored() {
  116. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  117. ash::switches::kIgnoreArcVmDevConf);
  118. }
  119. bool IsUreadaheadDisabled() {
  120. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  121. ash::switches::kArcDisableUreadahead);
  122. }
  123. ArcVmUreadaheadMode GetArcVmUreadaheadMode(SystemMemoryInfoCallback callback) {
  124. base::SystemMemoryInfoKB mem_info;
  125. DCHECK(callback);
  126. if (!callback.Run(&mem_info)) {
  127. LOG(ERROR) << "Failed to get system memory info";
  128. return ArcVmUreadaheadMode::DISABLED;
  129. }
  130. ArcVmUreadaheadMode mode = (mem_info.total > kReadaheadTotalMinMemoryInKb)
  131. ? IsUreadaheadDisabled()
  132. ? ArcVmUreadaheadMode::DISABLED
  133. : ArcVmUreadaheadMode::READAHEAD
  134. : ArcVmUreadaheadMode::DISABLED;
  135. if (base::CommandLine::ForCurrentProcess()->HasSwitch(
  136. ash::switches::kArcVmUreadaheadMode)) {
  137. const std::string value =
  138. base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
  139. ash::switches::kArcVmUreadaheadMode);
  140. if (value == kGenerate) {
  141. mode = ArcVmUreadaheadMode::GENERATE;
  142. } else if (value == kDisabled) {
  143. mode = ArcVmUreadaheadMode::DISABLED;
  144. } else {
  145. LOG(ERROR) << "Invalid parameter " << value << " for "
  146. << ash::switches::kArcVmUreadaheadMode;
  147. }
  148. }
  149. return mode;
  150. }
  151. bool ShouldArcAlwaysStart() {
  152. return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
  153. ash::switches::kArcStartMode) == kAlwaysStartWithNoPlayStore;
  154. }
  155. bool ShouldArcAlwaysStartWithNoPlayStore() {
  156. return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
  157. ash::switches::kArcStartMode) == kAlwaysStartWithNoPlayStore;
  158. }
  159. bool ShouldArcStartManually() {
  160. return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
  161. ash::switches::kArcStartMode) == kManualStart;
  162. }
  163. bool ShouldShowOptInForTesting() {
  164. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  165. ash::switches::kArcForceShowOptInUi);
  166. }
  167. bool IsArcKioskAvailable() {
  168. const auto* command_line = base::CommandLine::ForCurrentProcess();
  169. if (command_line->HasSwitch(ash::switches::kArcAvailability)) {
  170. std::string value =
  171. command_line->GetSwitchValueASCII(ash::switches::kArcAvailability);
  172. if (value == kAvailabilityInstalled)
  173. return true;
  174. return IsArcAvailable();
  175. }
  176. // TODO(hidehiko): Remove this when session_manager supports the new flag.
  177. if (command_line->HasSwitch(ash::switches::kArcAvailable))
  178. return true;
  179. // If not special kiosk device case, use general ARC check.
  180. return IsArcAvailable();
  181. }
  182. bool IsArcKioskMode() {
  183. return user_manager::UserManager::IsInitialized() &&
  184. user_manager::UserManager::Get()->IsLoggedInAsArcKioskApp();
  185. }
  186. bool IsRobotOrOfflineDemoAccountMode() {
  187. return user_manager::UserManager::IsInitialized() &&
  188. (user_manager::UserManager::Get()->IsLoggedInAsArcKioskApp() ||
  189. user_manager::UserManager::Get()->IsLoggedInAsPublicAccount());
  190. }
  191. bool IsArcAllowedForUser(const user_manager::User* user) {
  192. if (!user) {
  193. VLOG(1) << "No ARC for nullptr user.";
  194. return false;
  195. }
  196. // ARC is only supported for the following cases:
  197. // - Users have Gaia accounts;
  198. // - Active directory users;
  199. // - ARC kiosk session;
  200. // - Public Session users;
  201. // USER_TYPE_ARC_KIOSK_APP check is compatible with IsArcKioskMode()
  202. // above because ARC kiosk user is always the primary/active user of a
  203. // user session. The same for USER_TYPE_PUBLIC_ACCOUNT.
  204. if (!user->HasGaiaAccount() && !user->IsActiveDirectoryUser() &&
  205. user->GetType() != user_manager::USER_TYPE_ARC_KIOSK_APP &&
  206. user->GetType() != user_manager::USER_TYPE_PUBLIC_ACCOUNT) {
  207. VLOG(1) << "Users without GAIA or AD accounts, or not ARC kiosk apps are "
  208. "not supported in ARC.";
  209. return false;
  210. }
  211. return true;
  212. }
  213. bool IsArcOptInVerificationDisabled() {
  214. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  215. ash::switches::kDisableArcOptInVerification);
  216. }
  217. absl::optional<int> GetWindowTaskId(const aura::Window* window) {
  218. if (!window)
  219. return absl::nullopt;
  220. const std::string* window_app_id = exo::GetShellApplicationId(window);
  221. if (!window_app_id)
  222. return absl::nullopt;
  223. return GetTaskIdFromWindowAppId(*window_app_id);
  224. }
  225. absl::optional<int> GetTaskIdFromWindowAppId(const std::string& window_app_id) {
  226. int task_id;
  227. if (std::sscanf(window_app_id.c_str(), "org.chromium.arc.%d", &task_id) != 1)
  228. return absl::nullopt;
  229. return task_id;
  230. }
  231. absl::optional<int> GetWindowSessionId(const aura::Window* window) {
  232. if (!window)
  233. return absl::nullopt;
  234. const std::string* window_app_id = exo::GetShellApplicationId(window);
  235. if (!window_app_id)
  236. return absl::nullopt;
  237. return GetSessionIdFromWindowAppId(*window_app_id);
  238. }
  239. absl::optional<int> GetSessionIdFromWindowAppId(
  240. const std::string& window_app_id) {
  241. int session_id;
  242. if (std::sscanf(window_app_id.c_str(), "org.chromium.arc.session.%d",
  243. &session_id) != 1) {
  244. return absl::nullopt;
  245. }
  246. return session_id;
  247. }
  248. absl::optional<int> GetWindowTaskOrSessionId(const aura::Window* window) {
  249. auto result = GetWindowTaskId(window);
  250. if (result)
  251. return result;
  252. return GetWindowSessionId(window);
  253. }
  254. bool IsArcForceCacheAppIcon() {
  255. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  256. ash::switches::kArcGeneratePlayAutoInstall);
  257. }
  258. bool IsArcDataCleanupOnStartRequested() {
  259. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  260. ash::switches::kArcDataCleanupOnStart);
  261. }
  262. bool IsArcAppSyncFlowDisabled() {
  263. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  264. ash::switches::kArcDisableAppSync);
  265. }
  266. bool IsArcLocaleSyncDisabled() {
  267. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  268. ash::switches::kArcDisableLocaleSync);
  269. }
  270. bool IsArcPlayAutoInstallDisabled() {
  271. return base::CommandLine::ForCurrentProcess()->HasSwitch(
  272. ash::switches::kArcDisablePlayAutoInstall);
  273. }
  274. int32_t GetLcdDensityForDeviceScaleFactor(float device_scale_factor) {
  275. const auto* command_line = base::CommandLine::ForCurrentProcess();
  276. if (command_line->HasSwitch(ash::switches::kArcScale)) {
  277. const std::string dpi_str =
  278. command_line->GetSwitchValueASCII(ash::switches::kArcScale);
  279. int dpi;
  280. if (base::StringToInt(dpi_str, &dpi))
  281. return dpi;
  282. VLOG(1) << "Invalid Arc scale set. Using default.";
  283. }
  284. // TODO(b/131884992): Remove the logic to update default lcd density once
  285. // per-display-density is supported.
  286. constexpr float kEpsilon = 0.001;
  287. if (std::abs(device_scale_factor - display::kDsf_2_252) < kEpsilon)
  288. return 280;
  289. if (std::abs(device_scale_factor - 2.4f) < kEpsilon)
  290. return 280;
  291. if (std::abs(device_scale_factor - 1.6f) < kEpsilon)
  292. return 213; // TVDPI
  293. if (std::abs(device_scale_factor - display::kDsf_1_777) < kEpsilon)
  294. return 240; // HDPI
  295. if (std::abs(device_scale_factor - display::kDsf_1_8) < kEpsilon)
  296. return 240; // HDPI
  297. if (std::abs(device_scale_factor - display::kDsf_2_666) < kEpsilon)
  298. return 320; // XHDPI
  299. constexpr float kChromeScaleToAndroidScaleRatio = 0.75f;
  300. constexpr int32_t kDefaultDensityDpi = 160;
  301. return static_cast<int32_t>(
  302. std::max(1.0f, device_scale_factor * kChromeScaleToAndroidScaleRatio) *
  303. kDefaultDensityDpi);
  304. }
  305. int GetSystemPropertyInt(const std::string& property) {
  306. std::string output;
  307. if (!base::GetAppOutput({kCrosSystemPath, property}, &output))
  308. return -1;
  309. int output_int;
  310. return base::StringToInt(output, &output_int) ? output_int : -1;
  311. }
  312. JobDesc::JobDesc(const std::string& job_name,
  313. UpstartOperation operation,
  314. const std::vector<std::string>& environment)
  315. : job_name(job_name), operation(operation), environment(environment) {}
  316. JobDesc::~JobDesc() = default;
  317. JobDesc::JobDesc(const JobDesc& other) = default;
  318. void ConfigureUpstartJobs(std::deque<JobDesc> jobs,
  319. chromeos::VoidDBusMethodCallback callback) {
  320. if (jobs.empty()) {
  321. std::move(callback).Run(true);
  322. return;
  323. }
  324. if (jobs.front().operation == UpstartOperation::JOB_STOP_AND_START) {
  325. // Expand the restart operation into two, stop and start.
  326. jobs.front().operation = UpstartOperation::JOB_START;
  327. jobs.push_front({jobs.front().job_name, UpstartOperation::JOB_STOP,
  328. jobs.front().environment});
  329. }
  330. const auto& job_name = jobs.front().job_name;
  331. const auto& operation = jobs.front().operation;
  332. const auto& environment = jobs.front().environment;
  333. VLOG(1) << (operation == UpstartOperation::JOB_START ? "Starting "
  334. : "Stopping ")
  335. << DecodeJobName(job_name);
  336. auto wrapped_callback = base::BindOnce(&OnConfigureUpstartJobs,
  337. std::move(jobs), std::move(callback));
  338. switch (operation) {
  339. case UpstartOperation::JOB_START:
  340. ash::UpstartClient::Get()->StartJob(job_name, environment,
  341. std::move(wrapped_callback));
  342. break;
  343. case UpstartOperation::JOB_STOP:
  344. ash::UpstartClient::Get()->StopJob(job_name, environment,
  345. std::move(wrapped_callback));
  346. break;
  347. case UpstartOperation::JOB_STOP_AND_START:
  348. NOTREACHED();
  349. break;
  350. }
  351. }
  352. } // namespace arc