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 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/desks_storage/core/admin_template_service.h"
#include "ash/constants/ash_pref_names.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/values.h"
#include "components/app_constants/constants.h"
#include "components/desks_storage/core/desk_template_conversion.h"
#include "components/policy/policy_constants.h"
#include "components/services/app_service/public/cpp/app_types.h"
namespace desks_storage {
AdminTemplateService::AdminTemplateService(
const base::FilePath& user_data_dir_path,
const AccountId& account_id,
PrefService* pref_service)
: account_id_(account_id), pref_service_(pref_service) {
data_manager_ = std::make_unique<LocalDeskDataManager>(
user_data_dir_path, account_id,
LocalDeskDataManager::StorageLocation::kAppLaunchAutomationDir);
model_obs_.Observe(data_manager_.get());
auto& apps_cache_wrapper = apps::AppRegistryCacheWrapper::Get();
auto* apps_cache = apps_cache_wrapper.GetAppRegistryCache(account_id_);
// If we don't have an apps cache then we observe the wrapper to
// wait for it to be ready.
if (apps_cache) {
app_cache_obs_.Observe(apps_cache);
} else {
app_cache_wrapper_obs_.Observe(&apps_cache_wrapper);
}
pref_change_registrar_.Init(pref_service_);
pref_change_registrar_.Add(
ash::prefs::kAppLaunchAutomation,
base::BindRepeating(&AdminTemplateService::UpdateModelWithPolicy,
weak_ptr_factory_.GetWeakPtr()));
}
AdminTemplateService::~AdminTemplateService() = default;
void AdminTemplateService::UpdateModelWithPolicy() {
if (!IsReady()) {
return;
}
if (pref_service_ == nullptr) {
return;
}
// Query for the desired preference.
const PrefService::Preference* app_launch_automation_preference =
pref_service_->FindPreference(ash::prefs::kAppLaunchAutomation);
if (app_launch_automation_preference == nullptr) {
return;
}
const base::Value* pref_value = app_launch_automation_preference->GetValue();
CHECK(pref_value != nullptr);
if (pref_value->type() != base::Value::Type::LIST) {
return;
}
std::vector<std::unique_ptr<ash::DeskTemplate>> desk_templates =
desks_storage::desk_template_conversion::
ParseAdminTemplatesFromPolicyValue(*pref_value);
// If templates exist that aren't in the current policy we should delete them.
std::set<base::Uuid> desk_uuids_to_delete = data_manager_->GetAllEntryUuids();
for (auto& desk_template : desk_templates) {
// Something went wrong when parsing the template
if (desk_template == nullptr) {
continue;
}
// Something has gone wrong if the field isn't a dict.
if (desk_template->policy_definition().type() != base::Value::Type::DICT) {
continue;
}
// Query model to determine if this entry exists already.
auto get_entry_result =
data_manager_->GetEntryByUUID(desk_template->uuid());
auto entry_status = get_entry_result.status;
// If this template exists in the current policy then don't delete it after
// updating the locally stored policy. Note: this call is a noop if the
// template in question is a new template.
if (entry_status == desks_storage::DeskModel::GetEntryByUuidStatus::kOk ||
entry_status ==
desks_storage::DeskModel::GetEntryByUuidStatus::kNotFound) {
desk_uuids_to_delete.erase(desk_template->uuid());
// There was an error when retrieving the template, do nothing and delete
// the template.
} else {
continue;
}
// If the policy template already exists in the model and has been unchanged
// since the last policy update don't overwrite the data. This will
// preserve the user's window information for that template.
if (entry_status == desks_storage::DeskModel::GetEntryByUuidStatus::kOk &&
get_entry_result.entry->policy_definition() ==
desk_template->policy_definition()) {
continue;
}
// If the policy template exists in an updated form or is new then either
// add it to the model or overwrite the existing definition.
data_manager_->AddOrUpdateEntry(std::move(desk_template),
base::DoNothing());
}
// Remove all templates that aren't in the policy. If the policy is empty
// then this will remove all admin templates from the device.
for (auto uuid : desk_uuids_to_delete) {
data_manager_->DeleteEntry(uuid, base::DoNothing());
}
}
AdminTemplateModel* AdminTemplateService::GetAdminModel() {
return data_manager_.get();
}
DeskModel* AdminTemplateService::GetFullDeskModel() {
return data_manager_.get();
}
bool AdminTemplateService::IsReady() {
CHECK(data_manager_);
return data_manager_->IsReady() && is_cache_ready_;
}
void AdminTemplateService::DeskModelLoaded() {
is_cache_ready_ = WillAppRegistryCacheResolveAppIds();
UpdateModelWithPolicy();
}
void AdminTemplateService::OnAppRegistryCacheWillBeDestroyed(
apps::AppRegistryCache* cache) {
// Disallow updating the model. If this is happening we're likely going
// to be deallocated soon as well.
is_cache_ready_ = false;
app_cache_obs_.Reset();
}
void AdminTemplateService::OnAppTypeInitialized(apps::AppType app_type) {
// If the cache is already ready we don't need to update the model.
if (is_cache_ready_) {
return;
}
is_cache_ready_ = WillAppRegistryCacheResolveAppIds();
// If we're here it means that we have a policy that needs to be parsed but
// until this point the AppRegistryCache wasn't ready.
UpdateModelWithPolicy();
}
void AdminTemplateService::OnAppRegistryCacheAdded(
const AccountId& account_id) {
if (account_id != account_id_ || app_cache_obs_.IsObserving()) {
return;
}
auto* apps_cache =
apps::AppRegistryCacheWrapper::Get().GetAppRegistryCache(account_id);
app_cache_obs_.Observe(apps_cache);
}
bool AdminTemplateService::WillAppRegistryCacheResolveAppIds() {
if (!app_cache_obs_.IsObserving()) {
return false;
}
apps::AppRegistryCache* cache =
apps::AppRegistryCacheWrapper::Get().GetAppRegistryCache(account_id_);
CHECK(cache);
const std::set<apps::AppType>& initialized_types =
cache->InitializedAppTypes();
return initialized_types.contains(apps::AppType::kChromeApp);
}
} // namespace desks_storage
|