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>(&timestamp));
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>(&timestamp));
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