1//
2// Copyright (C) 2013 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "shill/external_task.h"
18
19#include <base/bind.h>
20#include <base/bind_helpers.h>
21
22#include "shill/error.h"
23#include "shill/event_dispatcher.h"
24#include "shill/process_manager.h"
25
26namespace shill {
27
28using base::FilePath;
29using std::map;
30using std::string;
31using std::vector;
32
33ExternalTask::ExternalTask(
34    ControlInterface* control,
35    ProcessManager* process_manager,
36    const base::WeakPtr<RPCTaskDelegate>& task_delegate,
37    const base::Callback<void(pid_t, int)>& death_callback)
38    : control_(control),
39      process_manager_(process_manager),
40      task_delegate_(task_delegate),
41      death_callback_(death_callback),
42      pid_(0) {
43  CHECK(task_delegate_);
44}
45
46ExternalTask::~ExternalTask() {
47  ExternalTask::Stop();
48}
49
50void ExternalTask::DestroyLater(EventDispatcher* dispatcher) {
51  // Passes ownership of |this| to Destroy.
52  dispatcher->PostTask(base::Bind(&Destroy, this));
53}
54
55bool ExternalTask::Start(const FilePath& program,
56                         const vector<string>& arguments,
57                         const map<string, string>& environment,
58                         bool terminate_with_parent,
59                         Error* error) {
60  CHECK(!pid_);
61  CHECK(!rpc_task_);
62
63  // Setup full environment variables.
64  std::unique_ptr<RPCTask> local_rpc_task(new RPCTask(control_, this));
65  map<string, string> env = local_rpc_task->GetEnvironment();
66  env.insert(environment.begin(), environment.end());
67
68  pid_t pid =
69      process_manager_->StartProcess(FROM_HERE,
70                                     program,
71                                     arguments,
72                                     env,
73                                     terminate_with_parent,
74                                     base::Bind(&ExternalTask::OnTaskDied,
75                                                base::Unretained(this)));
76
77  if (pid < 0) {
78    Error::PopulateAndLog(FROM_HERE, error, Error::kInternalError,
79                          string("Unable to spawn: ") +
80                          program.value().c_str());
81    return false;
82  }
83  pid_ = pid;
84  rpc_task_.reset(local_rpc_task.release());
85  return true;
86}
87
88void ExternalTask::Stop() {
89  if (pid_) {
90    process_manager_->StopProcess(pid_);
91    pid_ = 0;
92  }
93  rpc_task_.reset();
94}
95
96void ExternalTask::GetLogin(string* user, string* password) {
97  return task_delegate_->GetLogin(user, password);
98}
99
100void ExternalTask::Notify(const string& event,
101                          const map<string, string>& details) {
102  return task_delegate_->Notify(event, details);
103}
104
105void ExternalTask::OnTaskDied(int exit_status) {
106  CHECK(pid_);
107  LOG(INFO) << __func__ << "(" << pid_ << ", "
108            << exit_status << ")";
109  death_callback_.Run(pid_, exit_status);
110  pid_ = 0;
111  rpc_task_.reset();
112}
113
114// static
115void ExternalTask::Destroy(ExternalTask* task) {
116  delete task;
117}
118
119}  // namespace shill
120