File: admin_template_service.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (201 lines) | stat: -rw-r--r-- 6,661 bytes parent folder | download | duplicates (6)
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