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_logger.h"
6
7 #include <stdint.h>
8
9 #include "base/json/json_writer.h"
10 #include "base/time/time.h"
11 #include "base/values.h"
12 #include "chrome/browser/prefs/browser_prefs.h"
13 #include "chrome/common/pref_names.h"
14 #include "chrome/test/base/testing_browser_process.h"
15 #include "chrome/test/base/testing_profile.h"
16 #include "chromeos/dbus/cros_disks_client.h"
17 #include "chromeos/dbus/dbus_thread_manager.h"
18 #include "chromeos/disks/disk_mount_manager.h"
19 #include "chromeos/disks/mock_disk_mount_manager.h"
20 #include "chromeos/network/network_handler.h"
21 #include "components/arc/arc_prefs.h"
22 #include "components/policy/policy_constants.h"
23 #include "components/policy/proto/device_management_backend.pb.h"
24 #include "components/prefs/pref_service.h"
25 #include "components/prefs/testing_pref_service.h"
26 #include "content/public/test/browser_task_environment.h"
27 #include "testing/gmock/include/gmock/gmock.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29
30 using testing::_;
31 using testing::Invoke;
32 using testing::Mock;
33 using testing::WithArgs;
34
35 namespace em = enterprise_management;
36
37 namespace policy {
38
39 namespace {
40
41 constexpr char kStatefulMountPath[] = "/mnt/stateful_partition";
42 constexpr char kPackageName[] = "com.example.app";
43 constexpr char kPackageName2[] = "com.example.app2";
44 constexpr char kPackageName3[] = "com.example.app3";
45 constexpr char kPackageName4[] = "com.example.app4";
46 constexpr char kPackageName5[] = "com.example.app5";
47 const int kTimestamp = 123456;
48 const int64_t kAndroidId = 0x123456789ABCDEFL;
49
50 MATCHER_P(MatchProto, expected, "matches protobuf") {
51 return arg.SerializePartialAsString() == expected.SerializePartialAsString();
52 }
53
54 MATCHER_P(MatchEventExceptTimestamp, expected, "event matches") {
55 em::AppInstallReportLogEvent actual_event;
56 actual_event.MergeFrom(arg);
57 actual_event.clear_timestamp();
58
59 em::AppInstallReportLogEvent expected_event;
60 expected_event.MergeFrom(expected);
61 expected_event.clear_timestamp();
62
63 return actual_event.SerializePartialAsString() ==
64 expected_event.SerializePartialAsString();
65 }
66
ACTION_TEMPLATE(SaveTimestamp,HAS_1_TEMPLATE_PARAMS (int,k),AND_1_VALUE_PARAMS (out))67 ACTION_TEMPLATE(SaveTimestamp,
68 HAS_1_TEMPLATE_PARAMS(int, k),
69 AND_1_VALUE_PARAMS(out)) {
70 *out = testing::get<k>(args).timestamp();
71 }
72
ACTION_TEMPLATE(SaveAndroidId,HAS_1_TEMPLATE_PARAMS (int,k),AND_1_VALUE_PARAMS (out))73 ACTION_TEMPLATE(SaveAndroidId,
74 HAS_1_TEMPLATE_PARAMS(int, k),
75 AND_1_VALUE_PARAMS(out)) {
76 *out = testing::get<k>(args).android_id();
77 }
78
GetCurrentTimestamp()79 int64_t GetCurrentTimestamp() {
80 return (base::Time::Now() - base::Time::UnixEpoch()).InMicroseconds();
81 }
82
83 class MockAppInstallEventLoggerDelegate
84 : public AppInstallEventLogger::Delegate {
85 public:
86 MockAppInstallEventLoggerDelegate() = default;
87
GetAndroidId(AndroidIdCallback callback) const88 void GetAndroidId(AndroidIdCallback callback) const override {
89 GetAndroidId_(&callback);
90 }
91
92 MOCK_METHOD2(Add,
93 void(const std::set<std::string>& packages,
94 const em::AppInstallReportLogEvent& event));
95 MOCK_CONST_METHOD1(GetAndroidId_, void(AndroidIdCallback*));
96
97 private:
98 DISALLOW_COPY_AND_ASSIGN(MockAppInstallEventLoggerDelegate);
99 };
100
SetPolicy(policy::PolicyMap * map,const char * name,base::Value value)101 void SetPolicy(policy::PolicyMap* map, const char* name, base::Value value) {
102 map->Set(name, policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
103 policy::POLICY_SOURCE_CLOUD, std::move(value), nullptr);
104 }
105
106 } // namespace
107
108 class AppInstallEventLoggerTest : public testing::Test {
109 protected:
AppInstallEventLoggerTest()110 AppInstallEventLoggerTest()
111 : task_environment_(
112 base::test::TaskEnvironment::MainThreadType::UI,
113 base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {}
114
SetUp()115 void SetUp() override {
116 RegisterLocalState(pref_service_.registry());
117 TestingBrowserProcess::GetGlobal()->SetLocalState(&pref_service_);
118
119 chromeos::DBusThreadManager::Initialize();
120 chromeos::PowerManagerClient::InitializeFake();
121
122 chromeos::NetworkHandler::Initialize();
123
124 disk_mount_manager_ = new chromeos::disks::MockDiskMountManager;
125 chromeos::disks::DiskMountManager::InitializeForTesting(
126 disk_mount_manager_);
127 disk_mount_manager_->CreateDiskEntryForMountDevice(
128 chromeos::disks::DiskMountManager::MountPointInfo(
129 "/dummy/device/usb", kStatefulMountPath,
130 chromeos::MOUNT_TYPE_DEVICE, chromeos::disks::MOUNT_CONDITION_NONE),
131 "device_id", "device_label", "vendor", "product",
132 chromeos::DEVICE_TYPE_UNKNOWN, 1 << 20 /* total_size_in_bytes */,
133 false /* is_parent */, false /* has_media */, true /* on_boot_device */,
134 true /* on_removable_device */, "ext4");
135 }
136
TearDown()137 void TearDown() override {
138 logger_.reset();
139 task_environment_.RunUntilIdle();
140 chromeos::PowerManagerClient::Shutdown();
141 chromeos::NetworkHandler::Shutdown();
142 chromeos::DBusThreadManager::Shutdown();
143 chromeos::disks::DiskMountManager::Shutdown();
144 TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
145 }
146
147 // Runs |function|, verifies that the expected event is added to the logs for
148 // all apps in |packages| and its timestamp is set to the time at which the
149 // |function| is run.
150 template <typename T>
RunAndVerifyAdd(T function,const std::set<std::string> & packages)151 void RunAndVerifyAdd(T function, const std::set<std::string>& packages) {
152 Mock::VerifyAndClearExpectations(&delegate_);
153
154 SetAndroidId(0L);
155 int64_t timestamp = 0;
156 EXPECT_CALL(delegate_, Add(packages, MatchEventExceptTimestamp(event_)))
157 .WillOnce(SaveTimestamp<1>(×tamp));
158 const int64_t before = GetCurrentTimestamp();
159 function();
160 const int64_t after = GetCurrentTimestamp();
161 Mock::VerifyAndClearExpectations(&delegate_);
162
163 EXPECT_LE(before, timestamp);
164 EXPECT_GE(after, timestamp);
165 }
166
CreateLogger()167 void CreateLogger() {
168 event_.set_event_type(em::AppInstallReportLogEvent::CANCELED);
169 RunAndVerifyAdd(
170 [&]() {
171 logger_ =
172 std::make_unique<AppInstallEventLogger>(&delegate_, &profile_);
173 },
174 {});
175 event_.set_event_type(em::AppInstallReportLogEvent::SUCCESS);
176 }
177
SetAndroidId(int64_t android_id)178 void SetAndroidId(int64_t android_id) {
179 if (android_id) {
180 event_.set_android_id(android_id);
181 } else {
182 event_.clear_android_id();
183 }
184 EXPECT_CALL(delegate_, GetAndroidId_(_))
185 .WillOnce(WithArgs<0>(Invoke(
186 [=](AppInstallEventLogger::Delegate::AndroidIdCallback* callback) {
187 std::move(*callback).Run(android_id, kAndroidId);
188 })));
189 }
190
191 content::BrowserTaskEnvironment task_environment_;
192 TestingProfile profile_;
193 TestingPrefServiceSimple pref_service_;
194
195 // Owned by chromeos::disks::DiskMountManager.
196 chromeos::disks::MockDiskMountManager* disk_mount_manager_ = nullptr;
197
198 MockAppInstallEventLoggerDelegate delegate_;
199
200 em::AppInstallReportLogEvent event_;
201
202 std::unique_ptr<AppInstallEventLogger> logger_;
203
204 private:
205 DISALLOW_COPY_AND_ASSIGN(AppInstallEventLoggerTest);
206 };
207
208 // Store lists of apps for which push-install has been requested and is still
209 // pending. Clear all data related to app-install event log collection. Verify
210 // that the lists are cleared.
TEST_F(AppInstallEventLoggerTest,Clear)211 TEST_F(AppInstallEventLoggerTest, Clear) {
212 base::ListValue list;
213 list.AppendString("test");
214 profile_.GetPrefs()->Set(arc::prefs::kArcPushInstallAppsRequested, list);
215 profile_.GetPrefs()->Set(arc::prefs::kArcPushInstallAppsPending, list);
216 AppInstallEventLogger::Clear(&profile_);
217 EXPECT_TRUE(profile_.GetPrefs()
218 ->FindPreference(arc::prefs::kArcPushInstallAppsRequested)
219 ->IsDefaultValue());
220 EXPECT_TRUE(profile_.GetPrefs()
221 ->FindPreference(arc::prefs::kArcPushInstallAppsPending)
222 ->IsDefaultValue());
223 }
224
225 // Adds an event with a timestamp. Verifies that the event is added to the log
226 // and the timestamp is not changed.
TEST_F(AppInstallEventLoggerTest,Add)227 TEST_F(AppInstallEventLoggerTest, Add) {
228 CreateLogger();
229
230 event_.set_timestamp(kTimestamp);
231 std::unique_ptr<em::AppInstallReportLogEvent> event =
232 std::make_unique<em::AppInstallReportLogEvent>();
233 event->MergeFrom(event_);
234
235 SetAndroidId(kAndroidId);
236 EXPECT_CALL(delegate_,
237 Add(std::set<std::string>{kPackageName}, MatchProto(event_)));
238 logger_->Add(kPackageName, false /* gather_disk_space_info */,
239 std::move(event));
240 }
241
242 // Adds an event without a timestamp. Verifies that the event is added to the
243 // log and the timestamp is set to the current time.
TEST_F(AppInstallEventLoggerTest,AddSetsTimestamp)244 TEST_F(AppInstallEventLoggerTest, AddSetsTimestamp) {
245 CreateLogger();
246
247 std::unique_ptr<em::AppInstallReportLogEvent> event =
248 std::make_unique<em::AppInstallReportLogEvent>();
249 event->MergeFrom(event_);
250
251 RunAndVerifyAdd(
252 [&]() {
253 logger_->Add(kPackageName, false /* gather_disk_space_info */,
254 std::move(event));
255 },
256 {kPackageName});
257 }
258
259 // If an android id is available, verify it is added to the event.
TEST_F(AppInstallEventLoggerTest,AddsAndroidId)260 TEST_F(AppInstallEventLoggerTest, AddsAndroidId) {
261 CreateLogger();
262
263 std::unique_ptr<em::AppInstallReportLogEvent> event =
264 std::make_unique<em::AppInstallReportLogEvent>();
265 event->MergeFrom(event_);
266 event->clear_android_id();
267
268 SetAndroidId(kAndroidId);
269 int64_t android_id = 0;
270 EXPECT_CALL(delegate_, Add(std::set<std::string>{kPackageName},
271 MatchEventExceptTimestamp(event_)))
272 .WillOnce(SaveAndroidId<1>(&android_id));
273 logger_->Add(kPackageName, false /* gather_disk_space_info */,
274 std::move(event));
275 task_environment_.RunUntilIdle();
276 EXPECT_EQ(kAndroidId, android_id);
277 }
278
279 // If an android id isn't available, then the proto field should not be set.
TEST_F(AppInstallEventLoggerTest,DoesNotAddsAndroidId)280 TEST_F(AppInstallEventLoggerTest, DoesNotAddsAndroidId) {
281 CreateLogger();
282
283 std::unique_ptr<em::AppInstallReportLogEvent> event =
284 std::make_unique<em::AppInstallReportLogEvent>();
285 event->MergeFrom(event_);
286 event->clear_android_id();
287
288 SetAndroidId(0);
289 int64_t android_id = -1L;
290 EXPECT_CALL(delegate_, Add(std::set<std::string>{kPackageName},
291 MatchEventExceptTimestamp(event_)))
292 .WillOnce(SaveAndroidId<1>(&android_id));
293 logger_->Add(kPackageName, false /* gather_disk_space_info */,
294 std::move(event));
295 task_environment_.RunUntilIdle();
296 EXPECT_EQ(0, android_id);
297 }
298
299 // Adds an event with a timestamp, requesting that disk space information be
300 // added to it. Verifies that a background task is posted that consults the disk
301 // mount manager. Then, verifies that after the background task has run, the
302 // event is added.
303 //
304 // It is not possible to test that disk size information is retrieved correctly
305 // as a mounted stateful partition cannot be simulated in unit tests.
TEST_F(AppInstallEventLoggerTest,AddSetsDiskSpaceInfo)306 TEST_F(AppInstallEventLoggerTest, AddSetsDiskSpaceInfo) {
307 CreateLogger();
308
309 event_.set_timestamp(kTimestamp);
310 std::unique_ptr<em::AppInstallReportLogEvent> event =
311 std::make_unique<em::AppInstallReportLogEvent>();
312 event->MergeFrom(event_);
313
314 EXPECT_CALL(*disk_mount_manager_, disks()).Times(0);
315 EXPECT_CALL(delegate_, Add(_, _)).Times(0);
316 logger_->Add(kPackageName, true /* gather_disk_space_info */,
317 std::move(event));
318 Mock::VerifyAndClearExpectations(disk_mount_manager_);
319 Mock::VerifyAndClearExpectations(&delegate_);
320
321 EXPECT_CALL(*disk_mount_manager_, disks());
322 SetAndroidId(kAndroidId);
323 EXPECT_CALL(delegate_,
324 Add(std::set<std::string>{kPackageName}, MatchProto(event_)));
325 task_environment_.RunUntilIdle();
326 }
327
328 // Adds an event without a timestamp, requesting that disk space information be
329 // added to it. Verifies that a background task is posted that consults the disk
330 // mount manager. Then, verifies that after the background task has run, the
331 // event is added and its timestamp is set to the current time before posting
332 // the background task.
333 //
334 // It is not possible to test that disk size information is retrieved correctly
335 // as a mounted stateful partition cannot be simulated in unit tests.
TEST_F(AppInstallEventLoggerTest,AddSetsTimestampAndDiskSpaceInfo)336 TEST_F(AppInstallEventLoggerTest, AddSetsTimestampAndDiskSpaceInfo) {
337 CreateLogger();
338
339 std::unique_ptr<em::AppInstallReportLogEvent> event =
340 std::make_unique<em::AppInstallReportLogEvent>();
341 event->MergeFrom(event_);
342
343 EXPECT_CALL(*disk_mount_manager_, disks()).Times(0);
344 EXPECT_CALL(delegate_, Add(_, _)).Times(0);
345 const int64_t before = GetCurrentTimestamp();
346 logger_->Add(kPackageName, true /* gather_disk_space_info */,
347 std::move(event));
348 const int64_t after = GetCurrentTimestamp();
349 Mock::VerifyAndClearExpectations(disk_mount_manager_);
350 Mock::VerifyAndClearExpectations(&delegate_);
351
352 int64_t timestamp = 0;
353 EXPECT_CALL(*disk_mount_manager_, disks());
354 SetAndroidId(kAndroidId);
355 EXPECT_CALL(delegate_, Add(std::set<std::string>{kPackageName},
356 MatchEventExceptTimestamp(event_)))
357 .WillOnce(SaveTimestamp<1>(×tamp));
358 task_environment_.RunUntilIdle();
359
360 EXPECT_LE(before, timestamp);
361 EXPECT_GE(after, timestamp);
362 }
363
TEST_F(AppInstallEventLoggerTest,UpdatePolicy)364 TEST_F(AppInstallEventLoggerTest, UpdatePolicy) {
365 CreateLogger();
366
367 policy::PolicyMap new_policy_map;
368
369 base::DictionaryValue arc_policy;
370 auto list = std::make_unique<base::ListValue>();
371
372 // Test that REQUIRED, PREINSTALLED and FORCE_INSTALLED are markers to include
373 // app to the tracking. BLOCKED and AVAILABLE are excluded.
374 auto package1 = std::make_unique<base::DictionaryValue>();
375 package1->SetString("installType", "REQUIRED");
376 package1->SetString("packageName", kPackageName);
377 list->Append(std::move(package1));
378 auto package2 = std::make_unique<base::DictionaryValue>();
379 package2->SetString("installType", "PREINSTALLED");
380 package2->SetString("packageName", kPackageName2);
381 list->Append(std::move(package2));
382 auto package3 = std::make_unique<base::DictionaryValue>();
383 package3->SetString("installType", "FORCE_INSTALLED");
384 package3->SetString("packageName", kPackageName3);
385 list->Append(std::move(package3));
386 auto package4 = std::make_unique<base::DictionaryValue>();
387 package4->SetString("installType", "BLOCKED");
388 package4->SetString("packageName", kPackageName4);
389 list->Append(std::move(package4));
390 auto package5 = std::make_unique<base::DictionaryValue>();
391 package5->SetString("installType", "AVAILABLE");
392 package5->SetString("packageName", kPackageName5);
393 list->Append(std::move(package5));
394 arc_policy.SetList("applications", std::move(list));
395
396 std::string arc_policy_string;
397 base::JSONWriter::Write(arc_policy, &arc_policy_string);
398 SetPolicy(&new_policy_map, key::kArcEnabled, base::Value(true));
399 SetPolicy(&new_policy_map, key::kArcPolicy, base::Value(arc_policy_string));
400
401 // Expected CANCELED with empty package set
402 event_.set_event_type(em::AppInstallReportLogEvent::CANCELED);
403 SetAndroidId(kAndroidId);
404 EXPECT_CALL(delegate_,
405 Add(std::set<std::string>(), MatchEventExceptTimestamp(event_)));
406
407 logger_->OnPolicyUpdated(policy::PolicyNamespace(),
408 policy::PolicyMap() /* previous */, new_policy_map);
409 Mock::VerifyAndClearExpectations(&delegate_);
410
411 // Expected new packages added with disk info.
412 event_.set_event_type(em::AppInstallReportLogEvent::SERVER_REQUEST);
413 SetAndroidId(kAndroidId);
414 EXPECT_CALL(delegate_, Add(std::set<std::string>{kPackageName, kPackageName3},
415 MatchEventExceptTimestamp(event_)));
416 EXPECT_CALL(*disk_mount_manager_, disks());
417 task_environment_.RunUntilIdle();
418 Mock::VerifyAndClearExpectations(&delegate_);
419
420 // To avoid extra logging.
421 g_browser_process->local_state()->SetBoolean(prefs::kWasRestarted, true);
422 }
423
424 } // namespace policy
425