1// Copyright 2013 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/media_galleries/fileapi/safe_audio_video_checker.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "base/location.h"
10#include "base/logging.h"
11#include "base/process/process_handle.h"
12#include "chrome/common/chrome_utility_messages.h"
13#include "chrome/common/extensions/chrome_utility_extensions_messages.h"
14#include "content/public/browser/child_process_data.h"
15#include "content/public/browser/utility_process_host.h"
16#include "content/public/browser/browser_thread.h"
17#include "ipc/ipc_message_macros.h"
18#include "ipc/ipc_platform_file.h"
19
20SafeAudioVideoChecker::SafeAudioVideoChecker(
21    base::File file,
22    const storage::CopyOrMoveFileValidator::ResultCallback& callback)
23    : state_(INITIAL_STATE), file_(file.Pass()), callback_(callback) {
24  DCHECK(!callback.is_null());
25}
26
27void SafeAudioVideoChecker::Start() {
28  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
29  if (state_ != INITIAL_STATE)
30    return;
31  state_ = PINGED_STATE;
32
33  if (!file_.IsValid()) {
34    callback_.Run(base::File::FILE_ERROR_SECURITY);
35    state_ = FINISHED_STATE;
36    return;
37  }
38
39  utility_process_host_ = content::UtilityProcessHost::Create(
40      this, base::MessageLoopProxy::current())->AsWeakPtr();
41  utility_process_host_->Send(new ChromeUtilityMsg_StartupPing);
42}
43
44SafeAudioVideoChecker::~SafeAudioVideoChecker() {}
45
46void SafeAudioVideoChecker::OnProcessStarted() {
47  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
48  if (state_ != PINGED_STATE)
49    return;
50  state_ = STARTED_STATE;
51
52  if (utility_process_host_->GetData().handle == base::kNullProcessHandle)
53    DLOG(ERROR) << "Child process handle is null";
54  IPC::PlatformFileForTransit file_for_transit =
55      IPC::TakeFileHandleForProcess(file_.Pass(),
56                                    utility_process_host_->GetData().handle);
57  if (file_for_transit == IPC::InvalidPlatformFileForTransit()) {
58    OnCheckingFinished(false /* valid? */);
59    return;
60  }
61  const int64 kFileDecodeTimeInMS = 250;
62  utility_process_host_->Send(new ChromeUtilityMsg_CheckMediaFile(
63      kFileDecodeTimeInMS, file_for_transit));
64}
65
66void SafeAudioVideoChecker::OnCheckingFinished(bool valid) {
67  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
68  if (state_ != STARTED_STATE)
69    return;
70  state_ = FINISHED_STATE;
71
72  callback_.Run(valid ? base::File::FILE_OK :
73                        base::File::FILE_ERROR_SECURITY);
74}
75
76void SafeAudioVideoChecker::OnProcessCrashed(int exit_code) {
77  OnCheckingFinished(false);
78}
79
80bool SafeAudioVideoChecker::OnMessageReceived(const IPC::Message& message) {
81  bool handled = true;
82  IPC_BEGIN_MESSAGE_MAP(SafeAudioVideoChecker, message)
83    IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ProcessStarted,
84        OnProcessStarted)
85    IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_CheckMediaFile_Finished,
86        OnCheckingFinished)
87    IPC_MESSAGE_UNHANDLED(handled = false)
88  IPC_END_MESSAGE_MAP()
89  return handled;
90}
91