1 // Copyright (c) 2012 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.
5 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
8 #include "base/files/file_util.h"
9 #include "base/prefs/pref_change_registrar.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/threading/sequenced_worker_pool.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/chromeos/drive/debug_info_collector.h"
16 #include "chrome/browser/chromeos/drive/download_handler.h"
17 #include "chrome/browser/chromeos/drive/drive_pref_names.h"
18 #include "chrome/browser/chromeos/drive/file_cache.h"
19 #include "chrome/browser/chromeos/drive/file_system.h"
20 #include "chrome/browser/chromeos/drive/file_system_util.h"
21 #include "chrome/browser/chromeos/drive/job_scheduler.h"
22 #include "chrome/browser/chromeos/drive/resource_metadata.h"
23 #include "chrome/browser/chromeos/drive/resource_metadata_storage.h"
24 #include "chrome/browser/chromeos/file_manager/path_util.h"
25 #include "chrome/browser/chromeos/profiles/profile_util.h"
26 #include "chrome/browser/download/download_prefs.h"
27 #include "chrome/browser/download/download_service.h"
28 #include "chrome/browser/download/download_service_factory.h"
29 #include "chrome/browser/drive/drive_notification_manager_factory.h"
30 #include "chrome/browser/profiles/incognito_helpers.h"
31 #include "chrome/browser/profiles/profile.h"
32 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
33 #include "chrome/browser/signin/signin_manager_factory.h"
34 #include "chrome/common/chrome_version_info.h"
35 #include "chrome/common/pref_names.h"
36 #include "chrome/grit/generated_resources.h"
37 #include "components/drive/drive_api_util.h"
38 #include "components/drive/drive_app_registry.h"
39 #include "components/drive/drive_notification_manager.h"
40 #include "components/drive/event_logger.h"
41 #include "components/drive/service/drive_api_service.h"
42 #include "components/keyed_service/content/browser_context_dependency_manager.h"
43 #include "components/signin/core/browser/profile_oauth2_token_service.h"
44 #include "components/signin/core/browser/signin_manager.h"
45 #include "content/public/browser/browser_context.h"
46 #include "content/public/browser/browser_thread.h"
47 #include "content/public/browser/notification_service.h"
48 #include "content/public/common/user_agent.h"
49 #include "google_apis/drive/auth_service.h"
50 #include "storage/browser/fileapi/external_mount_points.h"
51 #include "ui/base/l10n/l10n_util.h"
53 using content::BrowserContext
;
54 using content::BrowserThread
;
59 // Name of the directory used to store metadata.
60 const base::FilePath::CharType kMetadataDirectory
[] = FILE_PATH_LITERAL("meta");
62 // Name of the directory used to store cached files.
63 const base::FilePath::CharType kCacheFileDirectory
[] =
64 FILE_PATH_LITERAL("files");
66 // Name of the directory used to store temporary files.
67 const base::FilePath::CharType kTemporaryFileDirectory
[] =
68 FILE_PATH_LITERAL("tmp");
70 // Returns a user agent string used for communicating with the Drive backend,
71 // both WAPI and Drive API. The user agent looks like:
73 // chromedrive-<VERSION> chrome-cc/none (<OS_CPU_INFO>)
74 // chromedrive-24.0.1274.0 chrome-cc/none (CrOS x86_64 0.4.0)
76 // TODO(satorux): Move this function to somewhere else: crbug.com/151605
77 std::string
GetDriveUserAgent() {
78 const char kDriveClientName
[] = "chromedrive";
80 chrome::VersionInfo version_info
;
81 const std::string version
= version_info
.Version();
83 // This part is <client_name>/<version>.
84 const char kLibraryInfo
[] = "chrome-cc/none";
86 const std::string os_cpu_info
= content::BuildOSCpuInfo();
88 // Add "gzip" to receive compressed data from the server.
89 // (see https://developers.google.com/drive/performance)
90 return base::StringPrintf("%s-%s %s (%s) (gzip)",
97 // Initializes FileCache and ResourceMetadata.
98 // Must be run on the same task runner used by |cache| and |resource_metadata|.
99 FileError
InitializeMetadata(
100 const base::FilePath
& cache_root_directory
,
101 internal::ResourceMetadataStorage
* metadata_storage
,
102 internal::FileCache
* cache
,
103 internal::ResourceMetadata
* resource_metadata
,
104 const base::FilePath
& downloads_directory
) {
105 // Files in temporary directory need not persist across sessions. Clean up
106 // the directory content while initialization.
107 base::DeleteFile(cache_root_directory
.Append(kTemporaryFileDirectory
),
109 if (!base::CreateDirectory(cache_root_directory
.Append(
110 kMetadataDirectory
)) ||
111 !base::CreateDirectory(cache_root_directory
.Append(
112 kCacheFileDirectory
)) ||
113 !base::CreateDirectory(cache_root_directory
.Append(
114 kTemporaryFileDirectory
))) {
115 LOG(WARNING
) << "Failed to create directories.";
116 return FILE_ERROR_FAILED
;
119 // Change permissions of cache file directory to u+rwx,og+x (711) in order to
120 // allow archive files in that directory to be mounted by cros-disks.
121 base::SetPosixFilePermissions(
122 cache_root_directory
.Append(kCacheFileDirectory
),
123 base::FILE_PERMISSION_USER_MASK
|
124 base::FILE_PERMISSION_EXECUTE_BY_GROUP
|
125 base::FILE_PERMISSION_EXECUTE_BY_OTHERS
);
127 internal::ResourceMetadataStorage::UpgradeOldDB(
128 metadata_storage
->directory_path());
130 if (!metadata_storage
->Initialize()) {
131 LOG(WARNING
) << "Failed to initialize the metadata storage.";
132 return FILE_ERROR_FAILED
;
135 if (!cache
->Initialize()) {
136 LOG(WARNING
) << "Failed to initialize the cache.";
137 return FILE_ERROR_FAILED
;
140 if (metadata_storage
->cache_file_scan_is_needed()) {
141 // Generate unique directory name.
142 const std::string
& dest_directory_name
= l10n_util::GetStringUTF8(
143 IDS_FILE_BROWSER_RECOVERED_FILES_FROM_GOOGLE_DRIVE_DIRECTORY_NAME
);
144 base::FilePath dest_directory
= downloads_directory
.Append(
145 base::FilePath::FromUTF8Unsafe(dest_directory_name
));
146 for (int uniquifier
= 1; base::PathExists(dest_directory
); ++uniquifier
) {
147 dest_directory
= downloads_directory
.Append(
148 base::FilePath::FromUTF8Unsafe(dest_directory_name
))
149 .InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", uniquifier
));
152 internal::ResourceMetadataStorage::RecoveredCacheInfoMap
153 recovered_cache_info
;
154 metadata_storage
->RecoverCacheInfoFromTrashedResourceMap(
155 &recovered_cache_info
);
157 LOG_IF(WARNING
, !recovered_cache_info
.empty())
158 << "DB could not be opened for some reasons. "
159 << "Recovering cache files to " << dest_directory
.value();
160 if (!cache
->RecoverFilesFromCacheDirectory(dest_directory
,
161 recovered_cache_info
)) {
162 LOG(WARNING
) << "Failed to recover cache files.";
163 return FILE_ERROR_FAILED
;
167 FileError error
= resource_metadata
->Initialize();
168 LOG_IF(WARNING
, error
!= FILE_ERROR_OK
)
169 << "Failed to initialize resource metadata. " << FileErrorToString(error
);
175 // Observes drive disable Preference's change.
176 class DriveIntegrationService::PreferenceWatcher
{
178 explicit PreferenceWatcher(PrefService
* pref_service
)
179 : pref_service_(pref_service
),
180 integration_service_(NULL
),
181 weak_ptr_factory_(this) {
182 DCHECK(pref_service
);
183 pref_change_registrar_
.Init(pref_service
);
184 pref_change_registrar_
.Add(
185 prefs::kDisableDrive
,
186 base::Bind(&PreferenceWatcher::OnPreferenceChanged
,
187 weak_ptr_factory_
.GetWeakPtr()));
190 void set_integration_service(DriveIntegrationService
* integration_service
) {
191 integration_service_
= integration_service
;
195 void OnPreferenceChanged() {
196 DCHECK(integration_service_
);
197 integration_service_
->SetEnabled(
198 !pref_service_
->GetBoolean(prefs::kDisableDrive
));
201 PrefService
* pref_service_
;
202 PrefChangeRegistrar pref_change_registrar_
;
203 DriveIntegrationService
* integration_service_
;
205 base::WeakPtrFactory
<PreferenceWatcher
> weak_ptr_factory_
;
206 DISALLOW_COPY_AND_ASSIGN(PreferenceWatcher
);
209 DriveIntegrationService::DriveIntegrationService(
211 PreferenceWatcher
* preference_watcher
,
212 DriveServiceInterface
* test_drive_service
,
213 const std::string
& test_mount_point_name
,
214 const base::FilePath
& test_cache_root
,
215 FileSystemInterface
* test_file_system
)
217 state_(NOT_INITIALIZED
),
219 mount_point_name_(test_mount_point_name
),
220 cache_root_directory_(!test_cache_root
.empty() ?
221 test_cache_root
: util::GetCacheRootPath(profile
)),
222 weak_ptr_factory_(this) {
223 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
224 DCHECK(profile
&& !profile
->IsOffTheRecord());
226 logger_
.reset(new EventLogger
);
227 base::SequencedWorkerPool
* blocking_pool
= BrowserThread::GetBlockingPool();
228 blocking_task_runner_
= blocking_pool
->GetSequencedTaskRunner(
229 blocking_pool
->GetSequenceToken());
231 ProfileOAuth2TokenService
* oauth_service
=
232 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
);
234 if (test_drive_service
) {
235 drive_service_
.reset(test_drive_service
);
237 drive_service_
.reset(new DriveAPIService(
239 g_browser_process
->system_request_context(),
240 blocking_task_runner_
.get(),
241 GURL(google_apis::DriveApiUrlGenerator::kBaseUrlForProduction
),
242 GURL(google_apis::DriveApiUrlGenerator::kBaseDownloadUrlForProduction
),
243 GetDriveUserAgent()));
245 scheduler_
.reset(new JobScheduler(
246 profile_
->GetPrefs(),
248 drive_service_
.get(),
249 blocking_task_runner_
.get()));
250 metadata_storage_
.reset(new internal::ResourceMetadataStorage(
251 cache_root_directory_
.Append(kMetadataDirectory
),
252 blocking_task_runner_
.get()));
253 cache_
.reset(new internal::FileCache(
254 metadata_storage_
.get(),
255 cache_root_directory_
.Append(kCacheFileDirectory
),
256 blocking_task_runner_
.get(),
257 NULL
/* free_disk_space_getter */));
258 drive_app_registry_
.reset(new DriveAppRegistry(drive_service_
.get()));
260 resource_metadata_
.reset(new internal::ResourceMetadata(
261 metadata_storage_
.get(), cache_
.get(), blocking_task_runner_
));
264 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
269 profile_
->GetPrefs(), logger_
.get(), cache_
.get(),
270 scheduler_
.get(), resource_metadata_
.get(),
271 blocking_task_runner_
.get(), file_task_runner_
.get(),
272 cache_root_directory_
.Append(kTemporaryFileDirectory
)));
273 download_handler_
.reset(new DownloadHandler(file_system()));
274 debug_info_collector_
.reset(new DebugInfoCollector(
275 resource_metadata_
.get(), file_system(), blocking_task_runner_
.get()));
277 if (preference_watcher
) {
278 preference_watcher_
.reset(preference_watcher
);
279 preference_watcher
->set_integration_service(this);
282 SetEnabled(drive::util::IsDriveEnabledForProfile(profile
));
285 DriveIntegrationService::~DriveIntegrationService() {
286 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
289 void DriveIntegrationService::Shutdown() {
290 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
292 weak_ptr_factory_
.InvalidateWeakPtrs();
294 DriveNotificationManager
* drive_notification_manager
=
295 DriveNotificationManagerFactory::FindForBrowserContext(profile_
);
296 if (drive_notification_manager
)
297 drive_notification_manager
->RemoveObserver(this);
299 RemoveDriveMountPoint();
300 debug_info_collector_
.reset();
301 download_handler_
.reset();
302 file_system_
.reset();
303 drive_app_registry_
.reset();
305 drive_service_
.reset();
308 void DriveIntegrationService::SetEnabled(bool enabled
) {
309 // If Drive is being disabled, ensure the download destination preference to
310 // be out of Drive. Do this before "Do nothing if not changed." because we
311 // want to run the check for the first SetEnabled() called in the constructor,
312 // which may be a change from false to false.
314 AvoidDriveAsDownloadDirecotryPreference();
316 // Do nothing if not changed.
317 if (enabled_
== enabled
)
323 case NOT_INITIALIZED
:
324 // If the initialization is not yet done, trigger it.
330 // If the state is INITIALIZING or REMOUNTING, at the end of the
331 // process, it tries to mounting (with re-checking enabled state).
332 // Do nothing for now.
336 // The integration service is already initialized. Add the mount point.
337 AddDriveMountPoint();
342 RemoveDriveMountPoint();
347 bool DriveIntegrationService::IsMounted() const {
348 if (mount_point_name_
.empty())
351 // Look up the registered path, and just discard it.
352 // GetRegisteredPath() returns true if the path is available.
353 base::FilePath unused
;
354 storage::ExternalMountPoints
* const mount_points
=
355 storage::ExternalMountPoints::GetSystemInstance();
356 DCHECK(mount_points
);
357 return mount_points
->GetRegisteredPath(mount_point_name_
, &unused
);
360 void DriveIntegrationService::AddObserver(
361 DriveIntegrationServiceObserver
* observer
) {
362 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
363 observers_
.AddObserver(observer
);
366 void DriveIntegrationService::RemoveObserver(
367 DriveIntegrationServiceObserver
* observer
) {
368 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
369 observers_
.RemoveObserver(observer
);
372 void DriveIntegrationService::OnNotificationReceived() {
373 file_system_
->CheckForUpdates();
374 drive_app_registry_
->Update();
377 void DriveIntegrationService::OnPushNotificationEnabled(bool enabled
) {
379 drive_app_registry_
->Update();
381 const char* status
= (enabled
? "enabled" : "disabled");
382 logger_
->Log(logging::LOG_INFO
, "Push notification is %s", status
);
385 void DriveIntegrationService::ClearCacheAndRemountFileSystem(
386 const base::Callback
<void(bool)>& callback
) {
387 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
388 DCHECK(!callback
.is_null());
390 if (state_
!= INITIALIZED
) {
395 RemoveDriveMountPoint();
398 // Reloads the Drive app registry.
399 drive_app_registry_
->Update();
400 // Resetting the file system clears resource metadata and cache.
401 file_system_
->Reset(base::Bind(
402 &DriveIntegrationService::AddBackDriveMountPoint
,
403 weak_ptr_factory_
.GetWeakPtr(),
407 void DriveIntegrationService::AddBackDriveMountPoint(
408 const base::Callback
<void(bool)>& callback
,
410 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
411 DCHECK(!callback
.is_null());
413 state_
= error
== FILE_ERROR_OK
? INITIALIZED
: NOT_INITIALIZED
;
415 if (error
!= FILE_ERROR_OK
|| !enabled_
) {
416 // Failed to reset, or Drive was disabled during the reset.
421 AddDriveMountPoint();
425 void DriveIntegrationService::AddDriveMountPoint() {
426 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
427 DCHECK_EQ(INITIALIZED
, state_
);
430 const base::FilePath
& drive_mount_point
=
431 util::GetDriveMountPointPath(profile_
);
432 if (mount_point_name_
.empty())
433 mount_point_name_
= drive_mount_point
.BaseName().AsUTF8Unsafe();
434 storage::ExternalMountPoints
* const mount_points
=
435 storage::ExternalMountPoints::GetSystemInstance();
436 DCHECK(mount_points
);
439 mount_points
->RegisterFileSystem(mount_point_name_
,
440 storage::kFileSystemTypeDrive
,
441 storage::FileSystemMountOption(),
445 logger_
->Log(logging::LOG_INFO
, "Drive mount point is added");
446 FOR_EACH_OBSERVER(DriveIntegrationServiceObserver
, observers_
,
447 OnFileSystemMounted());
451 void DriveIntegrationService::RemoveDriveMountPoint() {
452 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
454 if (!mount_point_name_
.empty()) {
455 job_list()->CancelAllJobs();
457 FOR_EACH_OBSERVER(DriveIntegrationServiceObserver
, observers_
,
458 OnFileSystemBeingUnmounted());
460 storage::ExternalMountPoints
* const mount_points
=
461 storage::ExternalMountPoints::GetSystemInstance();
462 DCHECK(mount_points
);
464 mount_points
->RevokeFileSystem(mount_point_name_
);
465 logger_
->Log(logging::LOG_INFO
, "Drive mount point is removed");
469 void DriveIntegrationService::Initialize() {
470 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
471 DCHECK_EQ(NOT_INITIALIZED
, state_
);
474 state_
= INITIALIZING
;
476 base::PostTaskAndReplyWithResult(
477 blocking_task_runner_
.get(),
479 base::Bind(&InitializeMetadata
,
480 cache_root_directory_
,
481 metadata_storage_
.get(),
483 resource_metadata_
.get(),
484 file_manager::util::GetDownloadsFolderForProfile(profile_
)),
485 base::Bind(&DriveIntegrationService::InitializeAfterMetadataInitialized
,
486 weak_ptr_factory_
.GetWeakPtr()));
489 void DriveIntegrationService::InitializeAfterMetadataInitialized(
491 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
492 DCHECK_EQ(INITIALIZING
, state_
);
494 SigninManagerBase
* signin_manager
=
495 SigninManagerFactory::GetForProfile(profile_
);
496 drive_service_
->Initialize(signin_manager
->GetAuthenticatedAccountId());
498 if (error
!= FILE_ERROR_OK
) {
499 LOG(WARNING
) << "Failed to initialize: " << FileErrorToString(error
);
501 // Cannot used Drive. Set the download destination preference out of Drive.
502 AvoidDriveAsDownloadDirecotryPreference();
504 // Back to NOT_INITIALIZED state. Then, re-running Initialize() should
505 // work if the error is recoverable manually (such as out of disk space).
506 state_
= NOT_INITIALIZED
;
510 // Initialize Download Handler for hooking downloads to the Drive folder.
511 content::DownloadManager
* download_manager
=
512 g_browser_process
->download_status_updater() ?
513 BrowserContext::GetDownloadManager(profile_
) : NULL
;
514 download_handler_
->Initialize(
516 cache_root_directory_
.Append(kTemporaryFileDirectory
));
518 // Install the handler also to incognito profile.
519 if (g_browser_process
->download_status_updater()) {
520 if (profile_
->HasOffTheRecordProfile()) {
521 download_handler_
->ObserveIncognitoDownloadManager(
522 BrowserContext::GetDownloadManager(
523 profile_
->GetOffTheRecordProfile()));
525 profile_notification_registrar_
.reset(new content::NotificationRegistrar
);
526 profile_notification_registrar_
->Add(
528 chrome::NOTIFICATION_PROFILE_CREATED
,
529 content::NotificationService::AllSources());
532 // Register for Google Drive invalidation notifications.
533 DriveNotificationManager
* drive_notification_manager
=
534 DriveNotificationManagerFactory::GetForBrowserContext(profile_
);
535 if (drive_notification_manager
) {
536 drive_notification_manager
->AddObserver(this);
537 const bool registered
=
538 drive_notification_manager
->push_notification_registered();
539 const char* status
= (registered
? "registered" : "not registered");
540 logger_
->Log(logging::LOG_INFO
, "Push notification is %s", status
);
542 if (drive_notification_manager
->push_notification_enabled())
543 drive_app_registry_
->Update();
546 state_
= INITIALIZED
;
548 // Mount only when the drive is enabled. Initialize is triggered by
549 // SetEnabled(true), but there is a change to disable it again during
550 // the metadata initialization, so we need to look this up again here.
552 AddDriveMountPoint();
555 void DriveIntegrationService::AvoidDriveAsDownloadDirecotryPreference() {
556 PrefService
* pref_service
= profile_
->GetPrefs();
557 if (util::IsUnderDriveMountPoint(
558 pref_service
->GetFilePath(::prefs::kDownloadDefaultDirectory
))) {
559 pref_service
->SetFilePath(
560 ::prefs::kDownloadDefaultDirectory
,
561 file_manager::util::GetDownloadsFolderForProfile(profile_
));
565 void DriveIntegrationService::Observe(
567 const content::NotificationSource
& source
,
568 const content::NotificationDetails
& details
) {
569 if (type
== chrome::NOTIFICATION_PROFILE_CREATED
) {
570 Profile
* created_profile
= content::Source
<Profile
>(source
).ptr();
571 if (created_profile
->IsOffTheRecord() &&
572 created_profile
->IsSameProfile(profile_
)) {
573 download_handler_
->ObserveIncognitoDownloadManager(
574 BrowserContext::GetDownloadManager(created_profile
));
579 //===================== DriveIntegrationServiceFactory =======================
581 DriveIntegrationServiceFactory::FactoryCallback
*
582 DriveIntegrationServiceFactory::factory_for_test_
= NULL
;
584 DriveIntegrationServiceFactory::ScopedFactoryForTest::ScopedFactoryForTest(
585 FactoryCallback
* factory_for_test
) {
586 factory_for_test_
= factory_for_test
;
589 DriveIntegrationServiceFactory::ScopedFactoryForTest::~ScopedFactoryForTest() {
590 factory_for_test_
= NULL
;
594 DriveIntegrationService
* DriveIntegrationServiceFactory::GetForProfile(
596 return static_cast<DriveIntegrationService
*>(
597 GetInstance()->GetServiceForBrowserContext(profile
, true));
601 DriveIntegrationService
* DriveIntegrationServiceFactory::FindForProfile(
603 return static_cast<DriveIntegrationService
*>(
604 GetInstance()->GetServiceForBrowserContext(profile
, false));
608 DriveIntegrationServiceFactory
* DriveIntegrationServiceFactory::GetInstance() {
609 return Singleton
<DriveIntegrationServiceFactory
>::get();
612 DriveIntegrationServiceFactory::DriveIntegrationServiceFactory()
613 : BrowserContextKeyedServiceFactory(
614 "DriveIntegrationService",
615 BrowserContextDependencyManager::GetInstance()) {
616 DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
617 DependsOn(DriveNotificationManagerFactory::GetInstance());
618 DependsOn(DownloadServiceFactory::GetInstance());
621 DriveIntegrationServiceFactory::~DriveIntegrationServiceFactory() {
624 content::BrowserContext
* DriveIntegrationServiceFactory::GetBrowserContextToUse(
625 content::BrowserContext
* context
) const {
626 return chrome::GetBrowserContextRedirectedInIncognito(context
);
629 KeyedService
* DriveIntegrationServiceFactory::BuildServiceInstanceFor(
630 content::BrowserContext
* context
) const {
631 Profile
* profile
= Profile::FromBrowserContext(context
);
633 DriveIntegrationService
* service
= NULL
;
634 if (!factory_for_test_
) {
635 DriveIntegrationService::PreferenceWatcher
* preference_watcher
= NULL
;
636 if (chromeos::IsProfileAssociatedWithGaiaAccount(profile
)) {
637 // Drive File System can be enabled.
639 new DriveIntegrationService::PreferenceWatcher(profile
->GetPrefs());
642 service
= new DriveIntegrationService(
643 profile
, preference_watcher
,
644 NULL
, std::string(), base::FilePath(), NULL
);
646 service
= factory_for_test_
->Run(profile
);