Skip to content

Commit

Permalink
[PreinstalledWebApps] Handle the case of force-installed default apps.
Browse files Browse the repository at this point in the history
The previous CL at crrev.com/c/3945016 introduced an additional policy
mapping for Preinstalled Web Apps which makes them undiscoverable by
install_url in case they're also force installed.

Bug: 1371300
Change-Id: I3e94bae32d84703ac986ce280f88c765fb2b649c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4020389
Reviewed-by: Dominick Ng <dominickn@chromium.org>
Reviewed-by: Glen Robertson <glenrob@chromium.org>
Commit-Queue: Andrew Rayskiy <greengrape@google.com>
Cr-Commit-Position: refs/heads/main@{#1073402}
  • Loading branch information
Andrew Rayskiy authored and Chromium LUCI CQ committed Nov 18, 2022
1 parent ab54ba6 commit fc4c349
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 112 deletions.
4 changes: 2 additions & 2 deletions chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -3557,6 +3557,8 @@ static_library("browser") {
"apps/app_service/metrics/app_service_metrics.h",
"apps/app_service/paused_apps.cc",
"apps/app_service/paused_apps.h",
"apps/app_service/policy_util.cc",
"apps/app_service/policy_util.h",
"apps/app_service/publishers/app_publisher.cc",
"apps/app_service/publishers/app_publisher.h",
"apps/app_service/publishers/extension_apps_enable_flow.cc",
Expand Down Expand Up @@ -4773,8 +4775,6 @@ static_library("browser") {
"apps/app_service/metrics/browser_to_tab_list.h",
"apps/app_service/metrics/website_metrics.cc",
"apps/app_service/metrics/website_metrics.h",
"apps/app_service/policy_util.cc",
"apps/app_service/policy_util.h",
"apps/app_service/publishers/arc_apps.cc",
"apps/app_service/publishers/arc_apps.h",
"apps/app_service/publishers/arc_apps_factory.cc",
Expand Down
198 changes: 110 additions & 88 deletions chrome/browser/apps/app_service/policy_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,121 +4,122 @@

#include "chrome/browser/apps/app_service/policy_util.h"

#include <array>
#include <utility>

#include "ash/webui/system_apps/public/system_web_app_type.h"
#include "base/containers/fixed_flat_map.h"
#include "base/no_destructor.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_piece.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
#include "chrome/browser/web_applications/web_app_id_constants.h"
#include "components/crx_file/id_util.h"
#include "components/services/app_service/public/cpp/app_update.h"

namespace {
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

namespace apps_util {

template <class Mapped>
using PolicyIdMappingPair = std::pair<base::StringPiece, Mapped>;
namespace {

using SystemWebAppMappingPair = PolicyIdMappingPair<ash::SystemWebAppType>;
#if BUILDFLAG(IS_CHROMEOS_ASH)

// This mapping excludes SWAs not included in official builds (like SAMPLE).
constexpr SystemWebAppMappingPair kSystemWebAppsMapping[] = {
{"file_manager", ash::SystemWebAppType::FILE_MANAGER},
{"settings", ash::SystemWebAppType::SETTINGS},
{"camera", ash::SystemWebAppType::CAMERA},
{"terminal", ash::SystemWebAppType::TERMINAL},
{"media", ash::SystemWebAppType::MEDIA},
{"help", ash::SystemWebAppType::HELP},
{"print_management", ash::SystemWebAppType::PRINT_MANAGEMENT},
{"scanning", ash::SystemWebAppType::SCANNING},
{"diagnostics", ash::SystemWebAppType::DIAGNOSTICS},
{"connectivity_diagnostics",
ash::SystemWebAppType::CONNECTIVITY_DIAGNOSTICS},
{"eche", ash::SystemWebAppType::ECHE},
{"crosh", ash::SystemWebAppType::CROSH},
{"personalization", ash::SystemWebAppType::PERSONALIZATION},
{"shortcut_customization", ash::SystemWebAppType::SHORTCUT_CUSTOMIZATION},
{"shimless_rma", ash::SystemWebAppType::SHIMLESS_RMA},
{"demo_mode", ash::SystemWebAppType::DEMO_MODE},
{"os_feedback", ash::SystemWebAppType::OS_FEEDBACK},
{"projector", ash::SystemWebAppType::PROJECTOR},
{"os_url_handler", ash::SystemWebAppType::OS_URL_HANDLER},
{"firmware_update", ash::SystemWebAppType::FIRMWARE_UPDATE},
{"os_flags", ash::SystemWebAppType::OS_FLAGS},
{"face_ml", ash::SystemWebAppType::FACE_ML}};

static_assert(std::rbegin(kSystemWebAppsMapping)->second ==
ash::SystemWebAppType::kMaxValue,
constexpr auto kSystemWebAppsMapping =
base::MakeFixedFlatMap<base::StringPiece, ash::SystemWebAppType>(
{{"file_manager", ash::SystemWebAppType::FILE_MANAGER},
{"settings", ash::SystemWebAppType::SETTINGS},
{"camera", ash::SystemWebAppType::CAMERA},
{"terminal", ash::SystemWebAppType::TERMINAL},
{"media", ash::SystemWebAppType::MEDIA},
{"help", ash::SystemWebAppType::HELP},
{"print_management", ash::SystemWebAppType::PRINT_MANAGEMENT},
{"scanning", ash::SystemWebAppType::SCANNING},
{"diagnostics", ash::SystemWebAppType::DIAGNOSTICS},
{"connectivity_diagnostics",
ash::SystemWebAppType::CONNECTIVITY_DIAGNOSTICS},
{"eche", ash::SystemWebAppType::ECHE},
{"crosh", ash::SystemWebAppType::CROSH},
{"personalization", ash::SystemWebAppType::PERSONALIZATION},
{"shortcut_customization",
ash::SystemWebAppType::SHORTCUT_CUSTOMIZATION},
{"shimless_rma", ash::SystemWebAppType::SHIMLESS_RMA},
{"demo_mode", ash::SystemWebAppType::DEMO_MODE},
{"os_feedback", ash::SystemWebAppType::OS_FEEDBACK},
{"projector", ash::SystemWebAppType::PROJECTOR},
{"os_url_handler", ash::SystemWebAppType::OS_URL_HANDLER},
{"firmware_update", ash::SystemWebAppType::FIRMWARE_UPDATE},
{"os_flags", ash::SystemWebAppType::OS_FLAGS},
{"face_ml", ash::SystemWebAppType::FACE_ML}});

constexpr ash::SystemWebAppType GetMaxSystemWebAppType() {
return base::ranges::max(kSystemWebAppsMapping, base::ranges::less{},
[](const auto& systemWebAppMappingPair) {
return systemWebAppMappingPair.second;
})
.second;
}

static_assert(GetMaxSystemWebAppType() == ash::SystemWebAppType::kMaxValue,
"Not all SWA types are listed in |system_web_apps_mapping|.");

using PreinstalledWebAppMappingPair = PolicyIdMappingPair<base::StringPiece>;
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

// Note that this mapping lists only selected Preinstalled Web Apps
// actively used in policies and is not meant to be exhaustive.
constexpr PreinstalledWebAppMappingPair kPreinstalledWebAppsMapping[] = {
{"cursive", web_app::kCursiveAppId},
{"canvas", web_app::kCanvasAppId}};

// Looks up what |policy_id| maps to in |arr|.
template <class Mapped, size_t N>
absl::optional<Mapped> LookupMappedValueByPolicyId(
const PolicyIdMappingPair<Mapped> (&arr)[N],
base::StringPiece policy_id) {
if (auto* ptr = base::ranges::find(arr, policy_id,
&PolicyIdMappingPair<Mapped>::first);
ptr != std::end(arr)) {
return ptr->second;
}
return {};
}

// Looks up what policy_id the provided |value| maps to in |arr|.
template <class Mapped, size_t N, class U>
absl::optional<base::StringPiece> LookupPolicyIdByMappedValue(
const PolicyIdMappingPair<Mapped> (&arr)[N],
const U& value) {
if (auto* ptr =
base::ranges::find(arr, value, &PolicyIdMappingPair<Mapped>::second);
ptr != std::end(arr)) {
return ptr->first;
}
return {};
constexpr auto kPreinstalledWebAppsMapping =
base::MakeFixedFlatMap<base::StringPiece, base::StringPiece>(
{{"cursive", web_app::kCursiveAppId},
{"canvas", web_app::kCanvasAppId}});

absl::optional<base::flat_map<base::StringPiece, base::StringPiece>>&
GetPreinstalledWebAppsMappingForTesting() {
static base::NoDestructor<
absl::optional<base::flat_map<base::StringPiece, base::StringPiece>>>
preinstalled_web_apps_mapping_for_testing;
return *preinstalled_web_apps_mapping_for_testing;
}

} // namespace

namespace apps_util {

bool IsSupportedAppTypePolicyId(base::StringPiece policy_id) {
return IsChromeAppPolicyId(policy_id) || IsArcAppPolicyId(policy_id) ||
IsWebAppPolicyId(policy_id) || IsSystemWebAppPolicyId(policy_id) ||
IsPreinstalledWebAppPolicyId(policy_id);
return IsChromeAppPolicyId(policy_id) ||
#if BUILDFLAG(IS_CHROMEOS_ASH)
IsArcAppPolicyId(policy_id) || IsSystemWebAppPolicyId(policy_id) ||
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
IsWebAppPolicyId(policy_id) || IsPreinstalledWebAppPolicyId(policy_id);
}

bool IsChromeAppPolicyId(base::StringPiece policy_id) {
return crx_file::id_util::IdIsValid(policy_id);
}

#if BUILDFLAG(IS_CHROMEOS_ASH)
bool IsArcAppPolicyId(base::StringPiece policy_id) {
return policy_id.find('.') != base::StringPiece::npos &&
!IsWebAppPolicyId(policy_id);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

bool IsWebAppPolicyId(base::StringPiece policy_id) {
return GURL{policy_id}.is_valid();
}

#if BUILDFLAG(IS_CHROMEOS_ASH)
bool IsSystemWebAppPolicyId(base::StringPiece policy_id) {
return LookupMappedValueByPolicyId(kSystemWebAppsMapping, policy_id)
.has_value();
return base::Contains(kSystemWebAppsMapping, policy_id);
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

bool IsPreinstalledWebAppPolicyId(base::StringPiece policy_id) {
return LookupMappedValueByPolicyId(kPreinstalledWebAppsMapping, policy_id)
.has_value();
if (auto& mapping = GetPreinstalledWebAppsMappingForTesting()) { // IN-TEST
return base::Contains(*mapping, policy_id);
}
return base::Contains(kPreinstalledWebAppsMapping, policy_id);
}

std::string TransformRawPolicyId(const std::string& raw_policy_id) {
Expand All @@ -132,14 +133,6 @@ std::string TransformRawPolicyId(const std::string& raw_policy_id) {

absl::optional<std::string> GetAppIdFromPolicyId(Profile* profile,
const std::string& policy_id) {
// Preinstalled Web Apps are mapped directly, so their |app_id| is not
// resolved through the App Service.
if (auto result =
LookupMappedValueByPolicyId(kPreinstalledWebAppsMapping, policy_id)) {
std::string preinstalled_web_app_id(*result);
return preinstalled_web_app_id;
};

// AppService might be absent in some cases, e.g. Arc++ Kiosk mode.
// TODO(b/240493670): Revisit this after app service is available in Kiosk.
if (apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) {
Expand All @@ -160,6 +153,7 @@ absl::optional<std::string> GetAppIdFromPolicyId(Profile* profile,
return policy_id;
}

#if BUILDFLAG(IS_CHROMEOS_ASH)
if (IsArcAppPolicyId(policy_id)) {
auto* arc_prefs = ArcAppListPrefs::Get(profile);
if (!arc_prefs) {
Expand All @@ -171,21 +165,14 @@ absl::optional<std::string> GetAppIdFromPolicyId(Profile* profile,
}
return app_id;
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

return {};
}

absl::optional<std::vector<std::string>> GetPolicyIdsFromAppId(
Profile* profile,
const std::string& app_id) {
// Preinstalled Web Apps are mapped directly, so their |policy_ids| are not
// resolved through the App Service.
if (auto result =
LookupPolicyIdByMappedValue(kPreinstalledWebAppsMapping, app_id)) {
std::string preinstalled_web_app_policy_id(*result);
return {{preinstalled_web_app_policy_id}};
}

// AppService might be absent in some cases, e.g. Arc++ Kiosk mode.
// TODO(b/240493670): Revisit this after app service is available in Kiosk.
if (apps::AppServiceProxyFactory::IsAppServiceAvailableForProfile(profile)) {
Expand All @@ -199,20 +186,55 @@ absl::optional<std::vector<std::string>> GetPolicyIdsFromAppId(
return policy_ids;
}

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Handle Arc++ ids
if (auto* arc_prefs = ArcAppListPrefs::Get(profile)) {
if (auto app_info = arc_prefs->GetApp(app_id)) {
return {{app_info->package_name}};
}
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

// Handle Chrome App ids
return {{app_id}};
}

#if BUILDFLAG(IS_CHROMEOS_ASH)
absl::optional<base::StringPiece> GetPolicyIdForSystemWebAppType(
ash::SystemWebAppType swa_type) {
return LookupPolicyIdByMappedValue(kSystemWebAppsMapping, swa_type);
for (const auto& [policy_id, mapped_swa_type] : kSystemWebAppsMapping) {
if (mapped_swa_type == swa_type) {
return policy_id;
}
}
return {};
}
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

absl::optional<base::StringPiece> GetPolicyIdForPreinstalledWebApp(
base::StringPiece app_id) {
if (const auto& test_mapping = GetPreinstalledWebAppsMappingForTesting()) {
for (const auto& [policy_id, mapped_app_id] : *test_mapping) {
if (mapped_app_id == app_id) {
return policy_id;
}
}
return {};
}

for (const auto& [policy_id, mapped_app_id] : kPreinstalledWebAppsMapping) {
if (mapped_app_id == app_id) {
return policy_id;
}
}
return {};
}

void SetPreinstalledWebAppsMappingForTesting( // IN-TEST
absl::optional<base::flat_map<base::StringPiece, base::StringPiece>>
preinstalled_web_apps_mapping_for_testing) {
GetPreinstalledWebAppsMappingForTesting() = // IN-TEST
std::move(preinstalled_web_apps_mapping_for_testing); // IN-TEST
}

} // namespace apps_util
23 changes: 22 additions & 1 deletion chrome/browser/apps/app_service/policy_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@
#include <string>
#include <vector>

#include "ash/webui/system_apps/public/system_web_app_type.h"
#include "base/containers/flat_map.h"
#include "base/strings/string_piece_forward.h"
#include "build/chromeos_buildflags.h"
#include "third_party/abseil-cpp/absl/types/optional.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/webui/system_apps/public/system_web_app_type.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

class Profile;

namespace apps_util {
Expand All @@ -34,14 +39,18 @@ bool IsSupportedAppTypePolicyId(base::StringPiece policy_id);
// Checks whether |policy_id| specifies a Chrome App.
bool IsChromeAppPolicyId(base::StringPiece policy_id);

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Checks whether |policy_id| specifies an Arc App.
bool IsArcAppPolicyId(base::StringPiece policy_id);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

// Checks whether |policy_id| specifies a Web App.
bool IsWebAppPolicyId(base::StringPiece policy_id);

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Checks whether |policy_id| specifies a System Web App.
bool IsSystemWebAppPolicyId(base::StringPiece policy_id);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

// Checks whether |policy_id| specifies a Preinstalled Web App.
bool IsPreinstalledWebAppPolicyId(base::StringPiece policy_id);
Expand Down Expand Up @@ -82,10 +91,22 @@ absl::optional<std::vector<std::string>> GetPolicyIdsFromAppId(
Profile*,
const std::string& app_id);

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Maps SystemWebAppType to a policy id.
// Returns absl::nullopt for apps not included in official builds.
absl::optional<base::StringPiece> GetPolicyIdForSystemWebAppType(
ash::SystemWebAppType);
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

// Returns the policy ID for a given preinstalled web app ID. Note that not all
// preinstalled web apps are supposed to have a policy ID (currently we only
// support EDU apps) - in all other cases this will return absl::nullopt.
absl::optional<base::StringPiece> GetPolicyIdForPreinstalledWebApp(
base::StringPiece preinstalled_web_app_id);

void SetPreinstalledWebAppsMappingForTesting(
absl::optional<base::flat_map<base::StringPiece, base::StringPiece>>
preinstalled_web_apps_mapping_for_testing);

} // namespace apps_util

Expand Down

0 comments on commit fc4c349

Please sign in to comment.