Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 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 "components/arc/arc_bridge_service.h" | |
| 6 | |
| 7 #include "base/files/file_path.h" | |
| 8 #include "base/files/file_util.h" | |
| 9 #include "base/prefs/pref_registry_simple.h" | |
| 10 #include "base/prefs/pref_service.h" | |
| 11 #include "base/task_runner_util.h" | |
| 12 #include "base/thread_task_runner_handle.h" | |
| 13 #include "chromeos/arc/bridge/common/arc_host_messages.h" | |
| 14 #include "chromeos/arc/bridge/common/arc_instance_messages.h" | |
| 15 #include "chromeos/dbus/arc_instance_client.h" | |
| 16 #include "chromeos/dbus/dbus_method_call_status.h" | |
| 17 #include "chromeos/dbus/dbus_thread_manager.h" | |
| 18 #include "components/arc/arc_pref_names.h" | |
| 19 #include "ipc/ipc_channel.h" | |
| 20 | |
| 21 namespace { | |
| 22 | |
| 23 const char kArcBridgeSocketPath[] = "/home/chronos/ArcBridge/bridge.sock"; | |
|
satorux1
2015/10/28 05:45:22
Please use const FilePath::CharType and FILE_PATH_
Luis Héctor Chávez
2015/10/28 17:19:14
Done.
| |
| 24 | |
| 25 bool EnsureParentDirectoryPresent(const std::string& socket_path) { | |
|
satorux1
2015/10/28 05:45:22
how about taking base::FilePath?
The caller shou
Luis Héctor Chávez
2015/10/28 17:19:14
Done.
hidehiko
2015/10/28 17:48:45
Or, in this case, we can inline the code in the ca
Luis Héctor Chávez
2015/10/28 21:06:32
Yep, that's cleaner. Done.
| |
| 26 base::FilePath path(socket_path); | |
| 27 return base::CreateDirectory(path.DirName()); | |
| 28 } | |
| 29 | |
| 30 bool SocketPermissions(const std::string& socket_path) { | |
|
satorux1
2015/10/28 05:45:22
Maybe SetSocketPermissions? std::string -> base::F
Luis Héctor Chávez
2015/10/28 17:19:14
Done.
hidehiko
2015/10/28 17:48:45
Or, does base::SetPosixFilePermissions work?
Luis Héctor Chávez
2015/10/28 21:06:32
Done.
| |
| 31 // TODO(lhchavez): Tighten the security around the socket by tying it to the | |
| 32 // user the instance will run as. | |
| 33 return HANDLE_EINTR(chmod(socket_path.c_str(), 0777)) == 0; | |
| 34 } | |
| 35 | |
| 36 } // namespace | |
| 37 | |
| 38 namespace arc { | |
| 39 | |
| 40 ArcBridgeService::ArcBridgeService( | |
| 41 const scoped_refptr<base::SequencedTaskRunner>& file_task_runner) | |
| 42 : ipc_thread_("ARC bridge listener"), | |
| 43 origin_task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
| 44 file_task_runner_(file_task_runner), | |
| 45 state_(ArcBridgeService::DISABLED) { | |
| 46 ipc_thread_.StartWithOptions( | |
| 47 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); | |
| 48 } | |
| 49 | |
| 50 ArcBridgeService::~ArcBridgeService() {} | |
| 51 | |
| 52 // static | |
| 53 void ArcBridgeService::RegisterPrefs(PrefRegistrySimple* registry) { | |
| 54 registry->RegisterBooleanPref(prefs::kArcEnabled, false); | |
| 55 } | |
| 56 | |
| 57 // static | |
| 58 bool ArcBridgeService::GetEnabledPref(PrefService* pref_service) { | |
| 59 // TODO(lhchavez): Once this is user-configurable, use the real pref. | |
| 60 return true; | |
| 61 } | |
| 62 | |
| 63 void ArcBridgeService::HandleStartup() { | |
| 64 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
| 65 if (state_ != ArcBridgeService::STOPPED) | |
|
hidehiko
2015/10/28 17:48:45
Is this expected case?
If yes, it's good to commen
Luis Héctor Chávez
2015/10/28 21:06:32
Done
| |
| 66 return; | |
| 67 base::PostTaskAndReplyWithResult( | |
|
hidehiko
2015/10/28 17:48:45
Just a suggestion.
1) It seems like directory crea
Luis Héctor Chávez
2015/10/28 21:06:32
Done.
| |
| 68 file_task_runner_.get(), | |
| 69 FROM_HERE, | |
| 70 base::Bind(&EnsureParentDirectoryPresent, kArcBridgeSocketPath), | |
| 71 base::Bind(&ArcBridgeService::SocketConnect, | |
| 72 base::Unretained(this), kArcBridgeSocketPath)); | |
|
satorux1
2015/10/28 05:45:22
How about using WeakPtrFactory and remove use of U
Luis Héctor Chávez
2015/10/28 17:19:14
All other KeyedServices I saw used Unretained(), b
| |
| 73 } | |
| 74 | |
| 75 void ArcBridgeService::Shutdown() { | |
|
hidehiko
2015/10/28 17:48:45
Looks to have a race issue?
If this is called whi
Luis Héctor Chávez
2015/10/28 21:06:32
All state transitions are now guarded.
| |
| 76 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
| 77 if (state_ != ArcBridgeService::CONNECTED && | |
| 78 state_ != ArcBridgeService::STARTING && | |
| 79 state_ != ArcBridgeService::READY) | |
|
hidehiko
2015/10/28 17:48:45
Maybe logging?
Luis Héctor Chávez
2015/10/28 21:06:32
Done.
| |
| 80 return; | |
| 81 ipc_channel_->Close(); | |
| 82 base::PostTaskAndReplyWithResult( | |
| 83 file_task_runner_.get(), | |
| 84 FROM_HERE, | |
| 85 base::Bind(&base::DeleteFile, base::FilePath(kArcBridgeSocketPath), | |
| 86 false), | |
| 87 base::Bind(&ArcBridgeService::FinishShutdownAfterSocketDeleted, | |
| 88 base::Unretained(this))); | |
| 89 } | |
| 90 | |
| 91 void ArcBridgeService::AddObserver(Observer* observer) { | |
| 92 observer_list_.AddObserver(observer); | |
| 93 } | |
| 94 | |
| 95 void ArcBridgeService::RemoveObserver(Observer* observer) { | |
| 96 observer_list_.RemoveObserver(observer); | |
| 97 } | |
| 98 | |
| 99 void ArcBridgeService::SetEnabled(bool enabled) { | |
| 100 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
| 101 | |
| 102 if ((!enabled && state_ == ArcBridgeService::DISABLED) || | |
| 103 (enabled && state_ != ArcBridgeService::DISABLED)) | |
| 104 return; | |
| 105 if (state_ != ArcBridgeService::DISABLED) { | |
| 106 Shutdown(); | |
| 107 NotifyStateChanged(ArcBridgeService::DISABLED); | |
| 108 return; | |
| 109 } | |
| 110 NotifyStateChanged(ArcBridgeService::STOPPED); | |
| 111 } | |
| 112 | |
| 113 bool ArcBridgeService::RegisterInputDevice( | |
| 114 const std::string& name, const std::string& device_type, | |
| 115 base::ScopedFD fd) { | |
|
satorux1
2015/10/28 05:45:22
on which thread should this be called? Add a DCHEC
Luis Héctor Chávez
2015/10/28 17:19:14
It doesn't matter, IPC::ChannelProxy has a thread-
hidehiko
2015/10/28 17:48:45
FYI: I believe this runs on the browser thread. As
Luis Héctor Chávez
2015/10/28 21:06:32
This can run on any thread (you're the second to m
| |
| 116 return ipc_channel_->Send(new ArcInstanceMsg_RegisterInputDevice( | |
| 117 name, device_type, base::FileDescriptor(fd.Pass()))); | |
| 118 } | |
| 119 | |
| 120 void ArcBridgeService::SocketConnect(const std::string& socket_path, | |
| 121 bool directory_creation_success) { | |
| 122 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
| 123 | |
| 124 if (!directory_creation_success) { | |
| 125 LOG(ERROR) << "Error creating directory for " << socket_path; | |
| 126 NotifyStateChanged(ArcBridgeService::ERROR); | |
| 127 return; | |
| 128 } | |
| 129 | |
| 130 if (!Connect(IPC::ChannelHandle(socket_path), | |
| 131 IPC::Channel::MODE_OPEN_NAMED_SERVER)) { | |
| 132 LOG(ERROR) << "Error connecting to " << socket_path; | |
| 133 NotifyStateChanged(ArcBridgeService::ERROR); | |
| 134 return; | |
| 135 } | |
| 136 | |
| 137 base::PostTaskAndReplyWithResult( | |
| 138 file_task_runner_.get(), | |
| 139 FROM_HERE, | |
| 140 base::Bind(&SocketPermissions, socket_path), | |
| 141 base::Bind(&ArcBridgeService::FinishConnectAfterSocketPermissions, | |
| 142 base::Unretained(this), socket_path)); | |
| 143 } | |
| 144 | |
| 145 void ArcBridgeService::FinishConnectAfterSocketPermissions( | |
| 146 const std::string& socket_path, bool socket_permissions_success) { | |
| 147 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
| 148 | |
| 149 if (!socket_permissions_success) { | |
| 150 LOG(ERROR) << "Error setting socket permissions for " << socket_path; | |
| 151 NotifyStateChanged(ArcBridgeService::ERROR); | |
| 152 return; | |
| 153 } | |
| 154 | |
| 155 // This will fail if the ArcInstanceService is not running on Chrome OS. | |
| 156 // Use base::Unretained since this is a KeyedService. | |
| 157 chromeos::DBusThreadManager::Get()->GetArcInstanceClient()->StartInstance( | |
| 158 socket_path, | |
| 159 base::Bind(&ArcBridgeService::OnInstanceStarted, base::Unretained(this))); | |
| 160 } | |
| 161 | |
| 162 | |
| 163 bool ArcBridgeService::Connect(const IPC::ChannelHandle& handle, | |
| 164 IPC::Channel::Mode mode) { | |
| 165 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
| 166 | |
| 167 ipc_channel_ = IPC::ChannelProxy::Create(handle, mode, this, | |
| 168 ipc_thread_.task_runner().get()); | |
| 169 if (!ipc_channel_) | |
| 170 return false; | |
| 171 NotifyStateChanged(ArcBridgeService::CONNECTED); | |
| 172 return true; | |
| 173 } | |
| 174 | |
| 175 void ArcBridgeService::OnInstanceReady() { | |
| 176 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
| 177 NotifyStateChanged(ArcBridgeService::READY); | |
| 178 } | |
| 179 | |
| 180 void ArcBridgeService::NotifyStateChanged(State state) { | |
| 181 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
| 182 if (state_ == state) | |
| 183 return; | |
| 184 state_ = state; | |
| 185 FOR_EACH_OBSERVER(Observer, observer_list_, OnStateChanged(state_)); | |
| 186 } | |
| 187 | |
| 188 void ArcBridgeService::FinishShutdownAfterSocketDeleted(bool socket_deleted) { | |
| 189 NotifyStateChanged(ArcBridgeService::STOPPED); | |
| 190 if (state_ != ArcBridgeService::STARTING && state_ != ArcBridgeService::READY) | |
| 191 return; | |
| 192 chromeos::DBusThreadManager::Get()->GetArcInstanceClient()->StopInstance( | |
| 193 base::Bind(&ArcBridgeService::OnInstanceStopped, base::Unretained(this))); | |
| 194 } | |
| 195 | |
| 196 bool ArcBridgeService::OnMessageReceived(const IPC::Message& message) { | |
| 197 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
| 198 bool handled = true; | |
| 199 | |
| 200 IPC_BEGIN_MESSAGE_MAP(ArcBridgeService, message) | |
| 201 IPC_MESSAGE_HANDLER(ArcInstanceHostMsg_InstanceReady, OnInstanceReady) | |
| 202 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 203 IPC_END_MESSAGE_MAP() | |
| 204 | |
| 205 if (!handled) | |
| 206 LOG(ERROR) << "Invalid message with type = " << message.type(); | |
| 207 return handled; | |
| 208 } | |
| 209 | |
| 210 void ArcBridgeService::OnInstanceStarted( | |
| 211 chromeos::DBusMethodCallStatus status) { | |
| 212 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
| 213 if (status != chromeos::DBUS_METHOD_CALL_SUCCESS) { | |
| 214 LOG(ERROR) << "ARC instance unable to start. Shutting down the bridge"; | |
| 215 Shutdown(); | |
| 216 return; | |
| 217 } | |
| 218 NotifyStateChanged(ArcBridgeService::STARTING); | |
| 219 } | |
| 220 | |
| 221 void ArcBridgeService::OnInstanceStopped( | |
| 222 chromeos::DBusMethodCallStatus status) { | |
| 223 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | |
| 224 NotifyStateChanged(ArcBridgeService::STOPPED); | |
| 225 } | |
| 226 | |
| 227 } // namespace arc | |
| OLD | NEW |