1 // Copyright 2018 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/app_install_event_log_collector.h"
6
7 #include "base/command_line.h"
8 #include "base/time/time.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/common/pref_names.h"
11 #include "chromeos/constants/chromeos_switches.h"
12 #include "chromeos/dbus/dbus_thread_manager.h"
13 #include "chromeos/network/network_handler.h"
14 #include "chromeos/network/network_state.h"
15 #include "chromeos/network/network_state_handler.h"
16 #include "chromeos/network/network_type_pattern.h"
17 #include "components/policy/proto/device_management_backend.pb.h"
18 #include "components/prefs/pref_service.h"
19 #include "content/public/browser/network_service_instance.h"
20 #include "third_party/cros_system_api/dbus/service_constants.h"
21
22 namespace em = enterprise_management;
23
24 namespace policy {
25
26 namespace {
27
CreateSessionChangeEvent(em::AppInstallReportLogEvent::SessionStateChangeType type)28 std::unique_ptr<em::AppInstallReportLogEvent> CreateSessionChangeEvent(
29 em::AppInstallReportLogEvent::SessionStateChangeType type) {
30 std::unique_ptr<em::AppInstallReportLogEvent> event =
31 std::make_unique<em::AppInstallReportLogEvent>();
32 event->set_event_type(em::AppInstallReportLogEvent::SESSION_STATE_CHANGE);
33 event->set_session_state_change_type(type);
34 return event;
35 }
36
GetOnlineState()37 bool GetOnlineState() {
38 chromeos::NetworkStateHandler::NetworkStateList network_state_list;
39 chromeos::NetworkHandler::Get()
40 ->network_state_handler()
41 ->GetNetworkListByType(
42 chromeos::NetworkTypePattern::Default(), true /* configured_only */,
43 false /* visible_only */, 0 /* limit */, &network_state_list);
44 for (const chromeos::NetworkState* network_state : network_state_list) {
45 if (network_state->connection_state() == shill::kStateOnline) {
46 return true;
47 }
48 }
49 return false;
50 }
51
SetTimestampFromTime(em::AppInstallReportLogEvent * event,base::Time time)52 void SetTimestampFromTime(em::AppInstallReportLogEvent* event,
53 base::Time time) {
54 event->set_timestamp((time - base::Time::UnixEpoch()).InMicroseconds());
55 }
56
57 } // namespace
58
AppInstallEventLogCollector(Delegate * delegate,Profile * profile,const std::set<std::string> & pending_packages)59 AppInstallEventLogCollector::AppInstallEventLogCollector(
60 Delegate* delegate,
61 Profile* profile,
62 const std::set<std::string>& pending_packages)
63 : delegate_(delegate),
64 profile_(profile),
65 online_(GetOnlineState()),
66 pending_packages_(pending_packages) {
67 chromeos::PowerManagerClient::Get()->AddObserver(this);
68 content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
69 // Might not be available in unit test.
70 arc::ArcPolicyBridge* const policy_bridge =
71 arc::ArcPolicyBridge::GetForBrowserContext(profile_);
72 if (policy_bridge) {
73 policy_bridge->AddObserver(this);
74 }
75 ArcAppListPrefs* const app_prefs = ArcAppListPrefs::Get(profile_);
76 if (app_prefs) {
77 app_prefs->AddObserver(this);
78 }
79 }
80
~AppInstallEventLogCollector()81 AppInstallEventLogCollector::~AppInstallEventLogCollector() {
82 ArcAppListPrefs* const app_prefs = ArcAppListPrefs::Get(profile_);
83 if (app_prefs) {
84 app_prefs->RemoveObserver(this);
85 }
86 chromeos::PowerManagerClient::Get()->RemoveObserver(this);
87 content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
88 arc::ArcPolicyBridge* const policy_bridge =
89 arc::ArcPolicyBridge::GetForBrowserContext(profile_);
90 if (policy_bridge) {
91 policy_bridge->RemoveObserver(this);
92 }
93 }
94
OnPendingPackagesChanged(const std::set<std::string> & pending_packages)95 void AppInstallEventLogCollector::OnPendingPackagesChanged(
96 const std::set<std::string>& pending_packages) {
97 pending_packages_ = pending_packages;
98 }
99
AddLoginEvent()100 void AppInstallEventLogCollector::AddLoginEvent() {
101 // Don't log in case session is restared or recovered from crash.
102 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
103 chromeos::switches::kLoginUser) ||
104 profile_->GetLastSessionExitType() == Profile::EXIT_CRASHED) {
105 return;
106 }
107
108 std::unique_ptr<em::AppInstallReportLogEvent> event =
109 CreateSessionChangeEvent(em::AppInstallReportLogEvent::LOGIN);
110 event->set_online(online_);
111 delegate_->AddForAllPackages(std::move(event));
112 }
113
AddLogoutEvent()114 void AppInstallEventLogCollector::AddLogoutEvent() {
115 // Don't log in case session is restared.
116 if (g_browser_process->local_state()->GetBoolean(prefs::kWasRestarted))
117 return;
118
119 delegate_->AddForAllPackages(
120 CreateSessionChangeEvent(em::AppInstallReportLogEvent::LOGOUT));
121 }
122
SuspendImminent(power_manager::SuspendImminent::Reason reason)123 void AppInstallEventLogCollector::SuspendImminent(
124 power_manager::SuspendImminent::Reason reason) {
125 delegate_->AddForAllPackages(
126 CreateSessionChangeEvent(em::AppInstallReportLogEvent::SUSPEND));
127 }
128
SuspendDone(const base::TimeDelta & sleep_duration)129 void AppInstallEventLogCollector::SuspendDone(
130 const base::TimeDelta& sleep_duration) {
131 delegate_->AddForAllPackages(
132 CreateSessionChangeEvent(em::AppInstallReportLogEvent::RESUME));
133 }
134
OnConnectionChanged(network::mojom::ConnectionType type)135 void AppInstallEventLogCollector::OnConnectionChanged(
136 network::mojom::ConnectionType type) {
137 const bool currently_online = GetOnlineState();
138 if (currently_online == online_) {
139 return;
140 }
141 online_ = currently_online;
142
143 std::unique_ptr<em::AppInstallReportLogEvent> event =
144 std::make_unique<em::AppInstallReportLogEvent>();
145 event->set_event_type(em::AppInstallReportLogEvent::CONNECTIVITY_CHANGE);
146 event->set_online(online_);
147 delegate_->AddForAllPackages(std::move(event));
148 }
149
OnCloudDpsRequested(base::Time time,const std::set<std::string> & package_names)150 void AppInstallEventLogCollector::OnCloudDpsRequested(
151 base::Time time,
152 const std::set<std::string>& package_names) {
153 for (const std::string& package_name : package_names) {
154 auto event = std::make_unique<em::AppInstallReportLogEvent>();
155 event->set_event_type(em::AppInstallReportLogEvent::CLOUDDPS_REQUEST);
156 SetTimestampFromTime(event.get(), time);
157 delegate_->Add(package_name, true /* gather_disk_space_info */,
158 std::move(event));
159 }
160 }
161
OnCloudDpsSucceeded(base::Time time,const std::set<std::string> & package_names)162 void AppInstallEventLogCollector::OnCloudDpsSucceeded(
163 base::Time time,
164 const std::set<std::string>& package_names) {
165 for (const std::string& package_name : package_names) {
166 auto event = std::make_unique<em::AppInstallReportLogEvent>();
167 event->set_event_type(em::AppInstallReportLogEvent::CLOUDDPS_RESPONSE);
168 SetTimestampFromTime(event.get(), time);
169 // Leave clouddps_response untouched.
170 delegate_->Add(package_name, true /* gather_disk_space_info */,
171 std::move(event));
172 }
173 }
174
OnCloudDpsFailed(base::Time time,const std::string & package_name,arc::mojom::InstallErrorReason reason)175 void AppInstallEventLogCollector::OnCloudDpsFailed(
176 base::Time time,
177 const std::string& package_name,
178 arc::mojom::InstallErrorReason reason) {
179 auto event = std::make_unique<em::AppInstallReportLogEvent>();
180 event->set_event_type(em::AppInstallReportLogEvent::CLOUDDPS_RESPONSE);
181 SetTimestampFromTime(event.get(), time);
182 event->set_clouddps_response(static_cast<int>(reason));
183 delegate_->Add(package_name, true /* gather_disk_space_info */,
184 std::move(event));
185 }
186
OnReportDirectInstall(base::Time time,const std::set<std::string> & package_names)187 void AppInstallEventLogCollector::OnReportDirectInstall(
188 base::Time time,
189 const std::set<std::string>& package_names) {
190 for (const std::string& package_name : package_names) {
191 auto event = std::make_unique<em::AppInstallReportLogEvent>();
192 event->set_event_type(em::AppInstallReportLogEvent::DIRECT_INSTALL);
193 SetTimestampFromTime(event.get(), time);
194 delegate_->Add(package_name, true /* gather_disk_space_info */,
195 std::move(event));
196 }
197 }
198
OnReportForceInstallMainLoopFailed(base::Time time,const std::set<std::string> & package_names)199 void AppInstallEventLogCollector::OnReportForceInstallMainLoopFailed(
200 base::Time time,
201 const std::set<std::string>& package_names) {
202 for (const std::string& package_name : package_names) {
203 auto event = std::make_unique<em::AppInstallReportLogEvent>();
204 event->set_event_type(
205 em::AppInstallReportLogEvent::CLOUDDPC_MAIN_LOOP_FAILED);
206 SetTimestampFromTime(event.get(), time);
207 delegate_->Add(package_name, true /* gather_disk_space_info */,
208 std::move(event));
209 }
210 }
211
OnInstallationStarted(const std::string & package_name)212 void AppInstallEventLogCollector::OnInstallationStarted(
213 const std::string& package_name) {
214 if (!pending_packages_.count(package_name)) {
215 return;
216 }
217
218 auto event = std::make_unique<em::AppInstallReportLogEvent>();
219 event->set_event_type(em::AppInstallReportLogEvent::INSTALLATION_STARTED);
220 delegate_->Add(package_name, true /* gather_disk_space_info */,
221 std::move(event));
222 }
223
OnInstallationFinished(const std::string & package_name,bool success)224 void AppInstallEventLogCollector::OnInstallationFinished(
225 const std::string& package_name,
226 bool success) {
227 if (!pending_packages_.count(package_name)) {
228 return;
229 }
230
231 auto event = std::make_unique<em::AppInstallReportLogEvent>();
232 event->set_event_type(
233 success ? em::AppInstallReportLogEvent::INSTALLATION_FINISHED
234 : em::AppInstallReportLogEvent::INSTALLATION_FAILED);
235 delegate_->Add(package_name, true /* gather_disk_space_info */,
236 std::move(event));
237 }
238
239 } // namespace policy
240