1// Copyright (c) 2012 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 "chrome/browser/chromeos/policy/user_policy_disk_cache.h"
6
7#include "base/bind.h"
8#include "base/files/file_util.h"
9#include "base/location.h"
10#include "base/logging.h"
11#include "base/message_loop/message_loop_proxy.h"
12#include "base/metrics/histogram.h"
13#include "base/sequenced_task_runner.h"
14#include "components/policy/core/common/cloud/enterprise_metrics.h"
15#include "policy/proto/device_management_local.pb.h"
16
17namespace em = enterprise_management;
18
19namespace policy {
20
21UserPolicyDiskCache::Delegate::~Delegate() {}
22
23UserPolicyDiskCache::UserPolicyDiskCache(
24    const base::WeakPtr<Delegate>& delegate,
25    const base::FilePath& backing_file_path,
26    scoped_refptr<base::SequencedTaskRunner> background_task_runner)
27    : delegate_(delegate),
28      backing_file_path_(backing_file_path),
29      origin_task_runner_(base::MessageLoopProxy::current()),
30      background_task_runner_(background_task_runner) {}
31
32void UserPolicyDiskCache::Load() {
33  DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
34  bool ret = background_task_runner_->PostTask(
35      FROM_HERE, base::Bind(&UserPolicyDiskCache::LoadOnFileThread, this));
36  DCHECK(ret);
37}
38
39void UserPolicyDiskCache::Store(
40    const em::CachedCloudPolicyResponse& policy) {
41  DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
42  background_task_runner_->PostTask(
43      FROM_HERE,
44      base::Bind(&UserPolicyDiskCache::StoreOnFileThread, this, policy));
45}
46
47UserPolicyDiskCache::~UserPolicyDiskCache() {}
48
49void UserPolicyDiskCache::LoadOnFileThread() {
50  DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
51
52  em::CachedCloudPolicyResponse cached_response;
53  if (!base::PathExists(backing_file_path_)) {
54    LoadDone(LOAD_RESULT_NOT_FOUND, cached_response);
55    return;
56  }
57
58  // Read the protobuf from the file.
59  std::string data;
60  if (!base::ReadFileToString(backing_file_path_, &data)) {
61    LOG(WARNING) << "Failed to read policy data from "
62                 << backing_file_path_.value();
63    LoadDone(LOAD_RESULT_READ_ERROR, cached_response);
64    return;
65  }
66
67  // Decode it.
68  if (!cached_response.ParseFromArray(data.c_str(), data.size())) {
69    LOG(WARNING) << "Failed to parse policy data read from "
70                 << backing_file_path_.value();
71    LoadDone(LOAD_RESULT_PARSE_ERROR, cached_response);
72    return;
73  }
74
75  LoadDone(LOAD_RESULT_SUCCESS, cached_response);
76}
77
78void UserPolicyDiskCache::LoadDone(
79    LoadResult result,
80    const em::CachedCloudPolicyResponse& policy) {
81  origin_task_runner_->PostTask(
82      FROM_HERE,
83      base::Bind(
84          &UserPolicyDiskCache::ReportResultOnUIThread, this, result, policy));
85}
86
87void UserPolicyDiskCache::ReportResultOnUIThread(
88    LoadResult result,
89    const em::CachedCloudPolicyResponse& policy) {
90  DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
91
92  switch (result) {
93    case LOAD_RESULT_NOT_FOUND:
94      break;
95    case LOAD_RESULT_READ_ERROR:
96    case LOAD_RESULT_PARSE_ERROR:
97      UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
98                                kMetricPolicyLoadFailed,
99                                policy::kMetricPolicySize);
100      break;
101    case LOAD_RESULT_SUCCESS:
102      UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
103                                kMetricPolicyLoadSucceeded,
104                                policy::kMetricPolicySize);
105      break;
106  }
107
108  if (delegate_.get())
109    delegate_->OnDiskCacheLoaded(result, policy);
110}
111
112void UserPolicyDiskCache::StoreOnFileThread(
113    const em::CachedCloudPolicyResponse& policy) {
114  DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
115  std::string data;
116  if (!policy.SerializeToString(&data)) {
117    LOG(WARNING) << "Failed to serialize policy data";
118    UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
119                              kMetricPolicyStoreFailed,
120                              policy::kMetricPolicySize);
121    return;
122  }
123
124  if (!base::CreateDirectory(backing_file_path_.DirName())) {
125    LOG(WARNING) << "Failed to create directory "
126                 << backing_file_path_.DirName().value();
127    UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
128                              kMetricPolicyStoreFailed,
129                              policy::kMetricPolicySize);
130    return;
131  }
132
133  int size = data.size();
134  if (base::WriteFile(backing_file_path_, data.c_str(), size) != size) {
135    LOG(WARNING) << "Failed to write " << backing_file_path_.value();
136    UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
137                              kMetricPolicyStoreFailed,
138                              policy::kMetricPolicySize);
139    return;
140  }
141  UMA_HISTOGRAM_ENUMERATION(policy::kMetricPolicy,
142                            kMetricPolicyStoreSucceeded,
143                            policy::kMetricPolicySize);
144}
145
146}  // namespace policy
147