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/imageburner/burn_controller.h"
8 #include "base/file_path.h"
9 #include "base/memory/weak_ptr.h"
10 #include "chrome/browser/chromeos/cros/burn_library.h"
11 #include "chrome/browser/chromeos/cros/cros_library.h"
12 #include "chrome/browser/chromeos/cros/network_library.h"
13 #include "chrome/browser/chromeos/imageburner/burn_manager.h"
14 #include "grit/generated_resources.h"
15 #include "googleurl/src/gurl.h"
18 namespace imageburner
{
22 const char kImageZipFileName
[] = "chromeos_image.bin.zip";
24 // 3.9GB. It is less than 4GB because true device size ussually varies a little.
25 const uint64 kMinDeviceSize
= static_cast<uint64
>(3.9 * 1000 * 1000 * 1000);
27 // Returns true when |disk| is a device on which we can burn recovery image.
28 bool IsBurnableDevice(const disks::DiskMountManager::Disk
& disk
) {
29 return disk
.is_parent() && !disk
.on_boot_device() && disk
.has_media() &&
30 (disk
.device_type() == DEVICE_TYPE_USB
||
31 disk
.device_type() == DEVICE_TYPE_SD
);
34 class BurnControllerImpl
35 : public BurnController
,
36 public disks::DiskMountManager::Observer
,
37 public BurnLibrary::Observer
,
38 public NetworkLibrary::NetworkManagerObserver
,
39 public StateMachine::Observer
,
40 public BurnManager::Delegate
,
41 public BurnManager::Observer
{
43 explicit BurnControllerImpl(BurnController::Delegate
* delegate
)
44 : burn_manager_(NULL
),
46 observing_burn_lib_(false),
49 disks::DiskMountManager::GetInstance()->AddObserver(this);
50 CrosLibrary::Get()->GetNetworkLibrary()->AddNetworkManagerObserver(this);
51 burn_manager_
= BurnManager::GetInstance();
52 burn_manager_
->AddObserver(this);
53 state_machine_
= burn_manager_
->state_machine();
54 state_machine_
->AddObserver(this);
57 virtual ~BurnControllerImpl() {
58 CrosLibrary::Get()->GetBurnLibrary()->RemoveObserver(this);
60 state_machine_
->RemoveObserver(this);
61 burn_manager_
->RemoveObserver(this);
62 CrosLibrary::Get()->GetNetworkLibrary()->RemoveNetworkManagerObserver(this);
63 disks::DiskMountManager::GetInstance()->RemoveObserver(this);
66 // disks::DiskMountManager::Observer interface.
67 virtual void OnDiskEvent(disks::DiskMountManager::DiskEvent event
,
68 const disks::DiskMountManager::Disk
* disk
) OVERRIDE
{
69 if (!IsBurnableDevice(*disk
))
71 if (event
== disks::DiskMountManager::DISK_ADDED
) {
72 delegate_
->OnDeviceAdded(*disk
);
73 } else if (event
== disks::DiskMountManager::DISK_REMOVED
) {
74 delegate_
->OnDeviceRemoved(*disk
);
75 if (burn_manager_
->target_device_path().value() == disk
->device_path())
76 ProcessError(IDS_IMAGEBURN_DEVICE_NOT_FOUND_ERROR
);
80 virtual void OnDeviceEvent(disks::DiskMountManager::DeviceEvent event
,
81 const std::string
& device_path
) OVERRIDE
{
84 virtual void OnMountEvent(
85 disks::DiskMountManager::MountEvent event
,
86 MountError error_code
,
87 const disks::DiskMountManager::MountPointInfo
& mount_info
) OVERRIDE
{
90 virtual void OnFormatEvent(
91 disks::DiskMountManager::FormatEvent event
,
92 FormatError error_code
,
93 const std::string
& device_path
) OVERRIDE
{
96 // BurnLibrary::Observer interface.
97 virtual void BurnProgressUpdated(BurnLibrary
* object
,
99 const ImageBurnStatus
& status
) OVERRIDE
{
105 ProcessError(IDS_IMAGEBURN_BURN_ERROR
);
108 delegate_
->OnProgress(BURNING
, status
.amount_burnt
, status
.total_size
);
111 delegate_
->OnProgress(UNZIPPING
, 0, 0);
114 ProcessError(IDS_IMAGEBURN_EXTRACTING_ERROR
);
116 case(UNZIP_COMPLETE
):
125 // NetworkLibrary::NetworkManagerObserver interface.
126 virtual void OnNetworkManagerChanged(NetworkLibrary
* obj
) OVERRIDE
{
127 if (state_machine_
->state() == StateMachine::INITIAL
&& CheckNetwork())
128 delegate_
->OnNetworkDetected();
130 if (state_machine_
->state() == StateMachine::DOWNLOADING
&&
132 ProcessError(IDS_IMAGEBURN_NETWORK_ERROR
);
135 // BurnManager::Observer override.
136 virtual void OnDownloadUpdated(
137 int64 received_bytes
,
139 const base::TimeDelta
& time_remaining
) OVERRIDE
{
140 if (state_machine_
->state() == StateMachine::DOWNLOADING
) {
141 delegate_
->OnProgressWithRemainingTime(DOWNLOADING
,
148 // BurnManager::Observer override.
149 virtual void OnDownloadCancelled() OVERRIDE
{
150 DownloadCompleted(false);
153 // BurnManager::Observer override.
154 virtual void OnDownloadCompleted() OVERRIDE
{
155 DownloadCompleted(true);
158 // StateMachine::Observer interface.
159 virtual void OnBurnStateChanged(StateMachine::State state
) OVERRIDE
{
160 if (state
== StateMachine::CANCELLED
) {
161 ProcessError(IDS_IMAGEBURN_USER_ERROR
);
162 } else if (state
!= StateMachine::INITIAL
&& !working_
) {
163 // User has started burn process, so let's start observing.
164 StartBurnImage(FilePath(), FilePath());
168 virtual void OnError(int error_message_id
) OVERRIDE
{
169 delegate_
->OnFail(error_message_id
);
173 // Part of BurnManager::Delegate interface.
174 virtual void OnImageDirCreated(bool success
) OVERRIDE
{
176 zip_image_file_path_
=
177 burn_manager_
->GetImageDir().Append(kImageZipFileName
);
178 burn_manager_
->FetchConfigFile(this);
180 DownloadCompleted(success
);
184 // Part of BurnManager::Delegate interface.
185 virtual void OnConfigFileFetched(bool success
,
186 const std::string
& image_file_name
,
187 const GURL
& image_download_url
) OVERRIDE
{
189 DownloadCompleted(false);
192 image_file_name_
= image_file_name
;
194 if (state_machine_
->download_finished()) {
199 if (!state_machine_
->download_started()) {
200 burn_manager_
->FetchImage(image_download_url
, zip_image_file_path_
);
201 state_machine_
->OnDownloadStarted();
205 // BurnController override.
206 virtual void Init() OVERRIDE
{
207 if (state_machine_
->state() == StateMachine::BURNING
) {
208 // There is nothing else left to do but observe burn progress.
210 } else if (state_machine_
->state() != StateMachine::INITIAL
) {
211 // User has started burn process, so let's start observing.
212 StartBurnImage(FilePath(), FilePath());
216 // BurnController override.
217 virtual std::vector
<disks::DiskMountManager::Disk
> GetBurnableDevices()
219 const disks::DiskMountManager::DiskMap
& disks
=
220 disks::DiskMountManager::GetInstance()->disks();
221 std::vector
<disks::DiskMountManager::Disk
> result
;
222 for (disks::DiskMountManager::DiskMap::const_iterator iter
= disks
.begin();
225 const disks::DiskMountManager::Disk
& disk
= *iter
->second
;
226 if (IsBurnableDevice(disk
))
227 result
.push_back(disk
);
232 // BurnController override.
233 virtual void CancelBurnImage() OVERRIDE
{
234 state_machine_
->OnCancelation();
237 // BurnController override.
238 // May be called with empty values if there is a handler that has started
239 // burning, and thus set the target paths.
240 virtual void StartBurnImage(const FilePath
& target_device_path
,
241 const FilePath
& target_file_path
) OVERRIDE
{
242 if (!target_device_path
.empty() && !target_file_path
.empty() &&
243 state_machine_
->new_burn_posible()) {
244 if (!CheckNetwork()) {
245 delegate_
->OnNoNetwork();
248 burn_manager_
->set_target_device_path(target_device_path
);
249 burn_manager_
->set_target_file_path(target_file_path
);
250 uint64 device_size
= GetDeviceSize(
251 burn_manager_
->target_device_path().value());
252 if (device_size
< kMinDeviceSize
) {
253 delegate_
->OnDeviceTooSmall(device_size
);
260 // Send progress signal now so ui doesn't hang in intial state until we get
262 delegate_
->OnProgress(DOWNLOADING
, 0, 0);
263 if (burn_manager_
->GetImageDir().empty()) {
264 burn_manager_
->CreateImageDir(this);
266 OnImageDirCreated(true);
271 void DownloadCompleted(bool success
) {
273 state_machine_
->OnDownloadFinished();
276 ProcessError(IDS_IMAGEBURN_DOWNLOAD_ERROR
);
281 if (!observing_burn_lib_
) {
282 CrosLibrary::Get()->GetBurnLibrary()->AddObserver(this);
283 observing_burn_lib_
= true;
285 if (state_machine_
->state() == StateMachine::BURNING
)
287 state_machine_
->OnBurnStarted();
289 CrosLibrary::Get()->GetBurnLibrary()->DoBurn(
290 zip_image_file_path_
,
291 image_file_name_
, burn_manager_
->target_file_path(),
292 burn_manager_
->target_device_path());
295 void FinalizeBurn() {
296 state_machine_
->OnSuccess();
297 burn_manager_
->ResetTargetPaths();
298 CrosLibrary::Get()->GetBurnLibrary()->RemoveObserver(this);
299 observing_burn_lib_
= false;
300 delegate_
->OnSuccess();
304 // Error is ussually detected by all existing Burn handlers, but only first
305 // one that calls ProcessError should actually process it.
306 void ProcessError(int message_id
) {
307 // If we are in intial state, error has already been dispached.
308 if (state_machine_
->state() == StateMachine::INITIAL
) {
309 // We don't need burn library since we are not the ones doing the cleanup.
310 if (observing_burn_lib_
) {
311 CrosLibrary::Get()->GetBurnLibrary()->RemoveObserver(this);
312 observing_burn_lib_
= false;
317 // Remember burner state, since it will be reset after OnError call.
318 StateMachine::State state
= state_machine_
->state();
320 // Dispach error. All hadlers' OnError event will be called before returning
321 // from this. This includes us, too.
322 state_machine_
->OnError(message_id
);
325 if (state
== StateMachine::DOWNLOADING
) {
326 burn_manager_
->CancelImageFetch();
327 } else if (state
== StateMachine::BURNING
) {
328 DCHECK(observing_burn_lib_
);
329 // Burn library doesn't send cancelled signal upon CancelBurnImage
331 CrosLibrary::Get()->GetBurnLibrary()->CancelBurnImage();
332 CrosLibrary::Get()->GetBurnLibrary()->RemoveObserver(this);
333 observing_burn_lib_
= false;
335 burn_manager_
->ResetTargetPaths();
338 int64
GetDeviceSize(const std::string
& device_path
) {
339 disks::DiskMountManager
* disk_mount_manager
=
340 disks::DiskMountManager::GetInstance();
341 const disks::DiskMountManager::Disk
* disk
=
342 disk_mount_manager
->FindDiskBySourcePath(device_path
);
343 return disk
? disk
->total_size_in_bytes() : 0;
346 bool CheckNetwork() {
347 return CrosLibrary::Get()->GetNetworkLibrary()->Connected();
350 FilePath zip_image_file_path_
;
351 std::string image_file_name_
;
352 BurnManager
* burn_manager_
;
353 StateMachine
* state_machine_
;
354 bool observing_burn_lib_
;
356 BurnController::Delegate
* delegate_
;
358 DISALLOW_COPY_AND_ASSIGN(BurnControllerImpl
);
364 BurnController
* BurnController::CreateBurnController(
365 content::WebContents
* web_contents
,
366 Delegate
* delegate
) {
367 return new BurnControllerImpl(delegate
);
370 } // namespace imageburner
371 } // namespace chromeos