Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: chrome/browser/chromeos/login/kiosk_browsertest.cc

Issue 491403003: Update cached kiosk app crx from usb stick. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "apps/app_window.h" 5 #include "apps/app_window.h"
6 #include "apps/app_window_registry.h" 6 #include "apps/app_window_registry.h"
7 #include "ash/desktop_background/desktop_background_controller.h" 7 #include "ash/desktop_background/desktop_background_controller.h"
8 #include "ash/desktop_background/desktop_background_controller_observer.h" 8 #include "ash/desktop_background/desktop_background_controller_observer.h"
9 #include "ash/shell.h" 9 #include "ash/shell.h"
10 #include "base/file_util.h" 10 #include "base/file_util.h"
11 #include "base/path_service.h" 11 #include "base/path_service.h"
12 #include "base/prefs/pref_service.h" 12 #include "base/prefs/pref_service.h"
13 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
15 #include "chrome/browser/browser_process.h" 15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/chrome_notification_types.h" 16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/chromeos/app_mode/fake_cws.h" 17 #include "chrome/browser/chromeos/app_mode/fake_cws.h"
18 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h" 18 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
19 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" 19 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
20 #include "chrome/browser/chromeos/file_manager/fake_disk_mount_manager.h"
20 #include "chrome/browser/chromeos/login/app_launch_controller.h" 21 #include "chrome/browser/chromeos/login/app_launch_controller.h"
21 #include "chrome/browser/chromeos/login/startup_utils.h" 22 #include "chrome/browser/chromeos/login/startup_utils.h"
22 #include "chrome/browser/chromeos/login/test/app_window_waiter.h" 23 #include "chrome/browser/chromeos/login/test/app_window_waiter.h"
23 #include "chrome/browser/chromeos/login/test/oobe_base_test.h" 24 #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
24 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" 25 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
25 #include "chrome/browser/chromeos/login/users/fake_user_manager.h" 26 #include "chrome/browser/chromeos/login/users/fake_user_manager.h"
26 #include "chrome/browser/chromeos/login/users/mock_user_manager.h" 27 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
27 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" 28 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
28 #include "chrome/browser/chromeos/login/wizard_controller.h" 29 #include "chrome/browser/chromeos/login/wizard_controller.h"
29 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h" 30 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
30 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h" 31 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
31 #include "chrome/browser/chromeos/profiles/profile_helper.h" 32 #include "chrome/browser/chromeos/profiles/profile_helper.h"
32 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h" 33 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
33 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h " 34 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h "
34 #include "chrome/browser/extensions/extension_service.h" 35 #include "chrome/browser/extensions/extension_service.h"
35 #include "chrome/browser/extensions/extension_test_message_listener.h" 36 #include "chrome/browser/extensions/extension_test_message_listener.h"
36 #include "chrome/browser/profiles/profile_impl.h" 37 #include "chrome/browser/profiles/profile_impl.h"
37 #include "chrome/browser/profiles/profiles_state.h" 38 #include "chrome/browser/profiles/profiles_state.h"
38 #include "chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h" 39 #include "chrome/browser/ui/webui/chromeos/login/kiosk_app_menu_handler.h"
39 #include "chrome/common/chrome_constants.h" 40 #include "chrome/common/chrome_constants.h"
40 #include "chrome/common/chrome_paths.h" 41 #include "chrome/common/chrome_paths.h"
41 #include "chrome/common/pref_names.h" 42 #include "chrome/common/pref_names.h"
42 #include "chromeos/chromeos_switches.h" 43 #include "chromeos/chromeos_switches.h"
43 #include "chromeos/dbus/cryptohome_client.h" 44 #include "chromeos/dbus/cryptohome_client.h"
45 #include "chromeos/disks/disk_mount_manager.h"
44 #include "components/signin/core/common/signin_pref_names.h" 46 #include "components/signin/core/common/signin_pref_names.h"
45 #include "content/public/browser/notification_observer.h" 47 #include "content/public/browser/notification_observer.h"
46 #include "content/public/browser/notification_registrar.h" 48 #include "content/public/browser/notification_registrar.h"
47 #include "content/public/browser/notification_service.h" 49 #include "content/public/browser/notification_service.h"
48 #include "content/public/test/browser_test_utils.h" 50 #include "content/public/test/browser_test_utils.h"
49 #include "extensions/browser/app_window/native_app_window.h" 51 #include "extensions/browser/app_window/native_app_window.h"
50 #include "extensions/browser/extension_system.h" 52 #include "extensions/browser/extension_system.h"
51 #include "google_apis/gaia/gaia_constants.h" 53 #include "google_apis/gaia/gaia_constants.h"
52 #include "google_apis/gaia/gaia_switches.h" 54 #include "google_apis/gaia/gaia_switches.h"
53 #include "google_apis/gaia/gaia_urls.h" 55 #include "google_apis/gaia/gaia_urls.h"
(...skipping 27 matching lines...) Expand all
81 // chrome/test/data/chromeos/app_mode/webstore/downloads/ 83 // chrome/test/data/chromeos/app_mode/webstore/downloads/
82 const char kTestOfflineEnabledKioskApp[] = "ajoggoflpgplnnjkjamcmbepjdjdnpdp"; 84 const char kTestOfflineEnabledKioskApp[] = "ajoggoflpgplnnjkjamcmbepjdjdnpdp";
83 85
84 // An app to test local fs data persistence across app update. V1 app writes 86 // An app to test local fs data persistence across app update. V1 app writes
85 // data into local fs. V2 app reads and verifies the data. 87 // data into local fs. V2 app reads and verifies the data.
86 // Webstore data json is in 88 // Webstore data json is in
87 // chrome/test/data/chromeos/app_mode/webstore/inlineinstall/ 89 // chrome/test/data/chromeos/app_mode/webstore/inlineinstall/
88 // detail/bmbpicmpniaclbbpdkfglgipkkebnbjf 90 // detail/bmbpicmpniaclbbpdkfglgipkkebnbjf
89 const char kTestLocalFsKioskApp[] = "bmbpicmpniaclbbpdkfglgipkkebnbjf"; 91 const char kTestLocalFsKioskApp[] = "bmbpicmpniaclbbpdkfglgipkkebnbjf";
90 92
93 const char kFakeUsbStickMountPath[] = "chromeos/app_mode/external_update/";
94
91 // Timeout while waiting for network connectivity during tests. 95 // Timeout while waiting for network connectivity during tests.
92 const int kTestNetworkTimeoutSeconds = 1; 96 const int kTestNetworkTimeoutSeconds = 1;
93 97
94 // Email of owner account for test. 98 // Email of owner account for test.
95 const char kTestOwnerEmail[] = "owner@example.com"; 99 const char kTestOwnerEmail[] = "owner@example.com";
96 100
97 const char kTestEnterpriseAccountId[] = "enterprise-kiosk-app@localhost"; 101 const char kTestEnterpriseAccountId[] = "enterprise-kiosk-app@localhost";
98 const char kTestEnterpriseServiceAccountId[] = "service_account@example.com"; 102 const char kTestEnterpriseServiceAccountId[] = "service_account@example.com";
99 const char kTestRefreshToken[] = "fake-refresh-token"; 103 const char kTestRefreshToken[] = "fake-refresh-token";
100 const char kTestUserinfoToken[] = "fake-userinfo-token"; 104 const char kTestUserinfoToken[] = "fake-userinfo-token";
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 runner_->Quit(); 222 runner_->Quit();
219 } 223 }
220 224
221 content::WebContents* web_contents_; 225 content::WebContents* web_contents_;
222 const std::string js_; 226 const std::string js_;
223 scoped_refptr<content::MessageLoopRunner> runner_; 227 scoped_refptr<content::MessageLoopRunner> runner_;
224 228
225 DISALLOW_COPY_AND_ASSIGN(JsConditionWaiter); 229 DISALLOW_COPY_AND_ASSIGN(JsConditionWaiter);
226 }; 230 };
227 231
232 class KioskFakeDiskMountManager : public file_manager::FakeDiskMountManager {
233 public:
234 explicit KioskFakeDiskMountManager(const std::string& usb_mount_path)
235 : usb_mount_path_(usb_mount_path) {}
236
237 virtual ~KioskFakeDiskMountManager() {}
238
239 void MountUsbStick() {
240 MountPath(usb_mount_path_, "", "", chromeos::MOUNT_TYPE_DEVICE);
241 }
242
243 void UnMountUsbStick() {
244 UnmountPath(usb_mount_path_,
245 UNMOUNT_OPTIONS_NONE,
246 disks::DiskMountManager::UnmountPathCallback());
247 }
248
249 private:
250 std::string usb_mount_path_;
251
252 DISALLOW_COPY_AND_ASSIGN(KioskFakeDiskMountManager);
253 };
254
228 } // namespace 255 } // namespace
229 256
230 class KioskTest : public OobeBaseTest { 257 class KioskTest : public OobeBaseTest {
231 public: 258 public:
232 KioskTest() : fake_cws_(new FakeCWS) { 259 KioskTest() : fake_cws_(new FakeCWS) {
233 set_exit_when_last_browser_closes(false); 260 set_exit_when_last_browser_closes(false);
234 } 261 }
235 262
236 virtual ~KioskTest() {} 263 virtual ~KioskTest() {}
237 264
(...skipping 646 matching lines...) Expand 10 before | Expand all | Expand 10 after
884 chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE, 911 chrome::NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE,
885 content::NotificationService::AllSources()).Wait(); 912 content::NotificationService::AllSources()).Wait();
886 } 913 }
887 914
888 class KioskUpdateTest : public KioskTest { 915 class KioskUpdateTest : public KioskTest {
889 public: 916 public:
890 KioskUpdateTest() {} 917 KioskUpdateTest() {}
891 virtual ~KioskUpdateTest() {} 918 virtual ~KioskUpdateTest() {}
892 919
893 protected: 920 protected:
921 virtual void SetUp() OVERRIDE {
922 base::FilePath test_data_dir;
923 PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
924 test_data_dir = test_data_dir.AppendASCII(kFakeUsbStickMountPath);
925 fake_disk_mount_manager_ =
926 new KioskFakeDiskMountManager(test_data_dir.value());
927 disks::DiskMountManager::InitializeForTesting(fake_disk_mount_manager_);
928
929 KioskTest::SetUp();
930 }
931
932 virtual void TearDown() OVERRIDE {
933 disks::DiskMountManager::Shutdown();
934
935 KioskTest::TearDown();
936 }
937
894 virtual void SetUpOnMainThread() OVERRIDE { 938 virtual void SetUpOnMainThread() OVERRIDE {
895 KioskTest::SetUpOnMainThread(); 939 KioskTest::SetUpOnMainThread();
896 } 940 }
897 941
898 void PreCacheApp(const std::string& app_id, 942 void PreCacheApp(const std::string& app_id,
899 const std::string& version, 943 const std::string& version,
900 const std::string& crx_file) { 944 const std::string& crx_file) {
901 set_test_app_id(app_id); 945 set_test_app_id(app_id);
902 set_test_app_version(version); 946 set_test_app_version(version);
903 set_test_crx_file(crx_file); 947 set_test_crx_file(crx_file);
(...skipping 20 matching lines...) Expand all
924 KioskAppManager::Get()->UpdateExternalCache(); 968 KioskAppManager::Get()->UpdateExternalCache();
925 waiter.Wait(); 969 waiter.Wait();
926 EXPECT_TRUE(waiter.loaded()); 970 EXPECT_TRUE(waiter.loaded());
927 std::string cached_version; 971 std::string cached_version;
928 base::FilePath file_path; 972 base::FilePath file_path;
929 EXPECT_TRUE( 973 EXPECT_TRUE(
930 manager->GetCachedCrx(test_app_id(), &file_path, &cached_version)); 974 manager->GetCachedCrx(test_app_id(), &file_path, &cached_version));
931 EXPECT_EQ(version, cached_version); 975 EXPECT_EQ(version, cached_version);
932 } 976 }
933 977
978 void SimulateUpdateAppFromUsbStick() {
979 KioskAppExternalUpdateWaiter waiter(KioskAppManager::Get(), test_app_id());
980 fake_disk_mount_manager_->MountUsbStick();
981 waiter.Wait();
982 fake_disk_mount_manager_->UnMountUsbStick();
983 }
984
934 void PreCacheAndLaunchApp(const std::string& app_id, 985 void PreCacheAndLaunchApp(const std::string& app_id,
935 const std::string& version, 986 const std::string& version,
936 const std::string& crx_file) { 987 const std::string& crx_file) {
937 set_test_app_id(app_id); 988 set_test_app_id(app_id);
938 set_test_app_version(version); 989 set_test_app_version(version);
939 set_test_crx_file(crx_file); 990 set_test_crx_file(crx_file);
940 PrepareAppLaunch(); 991 PrepareAppLaunch();
941 SimulateNetworkOnline(); 992 SimulateNetworkOnline();
942 LaunchApp(test_app_id(), false); 993 LaunchApp(test_app_id(), false);
943 WaitForAppLaunchSuccess(); 994 WaitForAppLaunchSuccess();
944 EXPECT_EQ(version, GetInstalledAppVersion().GetString()); 995 EXPECT_EQ(version, GetInstalledAppVersion().GetString());
945 } 996 }
946 997
947 private: 998 private:
999 class KioskAppExternalUpdateWaiter : KioskAppManagerObserver {
1000 public:
1001 KioskAppExternalUpdateWaiter(KioskAppManager* manager,
1002 const std::string& app_id)
1003 : runner_(NULL), manager_(manager), app_id_(app_id), quit_(false) {
1004 manager_->AddObserver(this);
1005 }
1006
1007 virtual ~KioskAppExternalUpdateWaiter() { manager_->RemoveObserver(this); }
1008
1009 void Wait() {
1010 if (quit_)
1011 return;
1012 runner_ = new content::MessageLoopRunner;
1013 runner_->Run();
1014 }
1015
1016 private:
1017 // KioskAppManagerObserver overrides:
1018 virtual void OnKioskAppCacheUpdated(const std::string& app_id) OVERRIDE {
1019 if (app_id_ != app_id)
1020 return;
1021 quit_ = true;
1022 if (runner_)
1023 runner_->Quit();
1024 }
1025
1026 scoped_refptr<content::MessageLoopRunner> runner_;
1027 KioskAppManager* manager_;
1028 const std::string app_id_;
1029 bool quit_;
1030
1031 DISALLOW_COPY_AND_ASSIGN(KioskAppExternalUpdateWaiter);
1032 };
1033
948 class AppDataLoadWaiter : public KioskAppManagerObserver { 1034 class AppDataLoadWaiter : public KioskAppManagerObserver {
949 public: 1035 public:
950 AppDataLoadWaiter(KioskAppManager* manager, 1036 AppDataLoadWaiter(KioskAppManager* manager,
951 const std::string& app_id, 1037 const std::string& app_id,
952 const std::string& version) 1038 const std::string& version)
953 : runner_(NULL), 1039 : runner_(NULL),
954 manager_(manager), 1040 manager_(manager),
955 loaded_(false), 1041 loaded_(false),
956 quit_(false), 1042 quit_(false),
957 app_id_(app_id), 1043 app_id_(app_id),
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
997 scoped_refptr<content::MessageLoopRunner> runner_; 1083 scoped_refptr<content::MessageLoopRunner> runner_;
998 KioskAppManager* manager_; 1084 KioskAppManager* manager_;
999 bool loaded_; 1085 bool loaded_;
1000 bool quit_; 1086 bool quit_;
1001 std::string app_id_; 1087 std::string app_id_;
1002 std::string version_; 1088 std::string version_;
1003 1089
1004 DISALLOW_COPY_AND_ASSIGN(AppDataLoadWaiter); 1090 DISALLOW_COPY_AND_ASSIGN(AppDataLoadWaiter);
1005 }; 1091 };
1006 1092
1093 // Owned by DiskMountManager.
1094 KioskFakeDiskMountManager* fake_disk_mount_manager_;
1095
1007 DISALLOW_COPY_AND_ASSIGN(KioskUpdateTest); 1096 DISALLOW_COPY_AND_ASSIGN(KioskUpdateTest);
1008 }; 1097 };
1009 1098
1010 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_LaunchOfflineEnabledAppNoNetwork) { 1099 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_LaunchOfflineEnabledAppNoNetwork) {
1011 PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, 1100 PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp,
1012 "1.0.0", 1101 "1.0.0",
1013 std::string(kTestOfflineEnabledKioskApp) + "_v1.crx"); 1102 std::string(kTestOfflineEnabledKioskApp) + "_v1.crx");
1014 } 1103 }
1015 1104
1016 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, LaunchOfflineEnabledAppNoNetwork) { 1105 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, LaunchOfflineEnabledAppNoNetwork) {
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
1102 test_app_id(), "ajoggoflpgplnnjkjamcmbepjdjdnpdp.crx", "2.0.0"); 1191 test_app_id(), "ajoggoflpgplnnjkjamcmbepjdjdnpdp.crx", "2.0.0");
1103 1192
1104 StartUIForAppLaunch(); 1193 StartUIForAppLaunch();
1105 SimulateNetworkOnline(); 1194 SimulateNetworkOnline();
1106 LaunchApp(test_app_id(), false); 1195 LaunchApp(test_app_id(), false);
1107 WaitForAppLaunchSuccess(); 1196 WaitForAppLaunchSuccess();
1108 1197
1109 EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString()); 1198 EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
1110 } 1199 }
1111 1200
1201 // Pre-cache v1 kiosk app.
1202 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_PRE_UsbStickUpdateAppNoNetwork) {
1203 PreCacheApp(kTestOfflineEnabledKioskApp,
1204 "1.0.0",
1205 std::string(kTestOfflineEnabledKioskApp) + "_v1.crx");
1206 }
1207
1208 // Take off network, plug in usb stick with a v2 app.
1209 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_UsbStickUpdateAppNoNetwork) {
1210 set_test_app_id(kTestOfflineEnabledKioskApp);
1211 StartUIForAppLaunch();
1212 SimulateNetworkOffline();
1213 LaunchApp(test_app_id(), false);
1214 WaitForAppLaunchSuccess();
1215 EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
1216
1217 // Simulate mounting of usb stick with v2 app on the stick.
1218 SimulateUpdateAppFromUsbStick();
1219
1220 // The v2 kiosk app is copied into external cache, but won't be loaded
1221 // until next time the device is started.
1222 EXPECT_EQ("1.0.0", GetInstalledAppVersion().GetString());
1223 }
1224
1225 // Restart the device, verify the app has been updated to v2.
1226 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, UsbStickUpdateAppNoNetwork) {
1227 // Verify the kiosk app has been updated to v2.
1228 set_test_app_id(kTestOfflineEnabledKioskApp);
1229 StartUIForAppLaunch();
1230 SimulateNetworkOffline();
1231 LaunchApp(test_app_id(), false);
1232 WaitForAppLaunchSuccess();
1233 EXPECT_EQ("2.0.0", GetInstalledAppVersion().GetString());
1234 }
1235
1112 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_PermissionChange) { 1236 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PRE_PermissionChange) {
1113 PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp, 1237 PreCacheAndLaunchApp(kTestOfflineEnabledKioskApp,
1114 "2.0.0", 1238 "2.0.0",
1115 std::string(kTestOfflineEnabledKioskApp) + ".crx"); 1239 std::string(kTestOfflineEnabledKioskApp) + ".crx");
1116 } 1240 }
1117 1241
1118 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PermissionChange) { 1242 IN_PROC_BROWSER_TEST_F(KioskUpdateTest, PermissionChange) {
1119 set_test_app_id(kTestOfflineEnabledKioskApp); 1243 set_test_app_id(kTestOfflineEnabledKioskApp);
1120 set_test_app_version("2.0.0"); 1244 set_test_app_version("2.0.0");
1121 set_test_crx_file(test_app_id() + "_v2_permission_change.crx"); 1245 set_test_crx_file(test_app_id() + "_v2_permission_change.crx");
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
1372 content::WindowedNotificationObserver( 1496 content::WindowedNotificationObserver(
1373 chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE, 1497 chrome::NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE,
1374 content::NotificationService::AllSources()).Wait(); 1498 content::NotificationService::AllSources()).Wait();
1375 1499
1376 // Wait for the wallpaper to load. 1500 // Wait for the wallpaper to load.
1377 WaitForWallpaper(); 1501 WaitForWallpaper();
1378 EXPECT_TRUE(wallpaper_loaded()); 1502 EXPECT_TRUE(wallpaper_loaded());
1379 } 1503 }
1380 1504
1381 } // namespace chromeos 1505 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698