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