Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. | 13 // limitations under the License. |
| 14 | 14 |
| 15 #include "client/crashpad_client.h" | 15 #include "client/crashpad_client.h" |
| 16 | 16 |
| 17 #include <errno.h> | |
| 17 #include <mach/mach.h> | 18 #include <mach/mach.h> |
| 19 #include <pthread.h> | |
| 18 #include <sys/wait.h> | 20 #include <sys/wait.h> |
| 19 #include <unistd.h> | 21 #include <unistd.h> |
| 20 | 22 |
| 21 #include "base/logging.h" | 23 #include "base/logging.h" |
| 22 #include "base/mac/mach_logging.h" | 24 #include "base/mac/mach_logging.h" |
| 23 #include "base/posix/eintr_wrapper.h" | 25 #include "base/posix/eintr_wrapper.h" |
| 24 #include "base/strings/stringprintf.h" | 26 #include "base/strings/stringprintf.h" |
| 27 #include "util/mac/mac_util.h" | |
| 25 #include "util/mach/child_port_handshake.h" | 28 #include "util/mach/child_port_handshake.h" |
| 26 #include "util/mach/exception_ports.h" | 29 #include "util/mach/exception_ports.h" |
| 27 #include "util/mach/mach_extensions.h" | 30 #include "util/mach/mach_extensions.h" |
| 31 #include "util/mach/mach_message.h" | |
| 32 #include "util/mach/notify_server.h" | |
| 33 #include "util/misc/clock.h" | |
| 28 #include "util/misc/implicit_cast.h" | 34 #include "util/misc/implicit_cast.h" |
| 29 #include "util/posix/close_multiple.h" | 35 #include "util/posix/close_multiple.h" |
| 30 | 36 |
| 31 namespace crashpad { | 37 namespace crashpad { |
| 32 | 38 |
| 33 namespace { | 39 namespace { |
| 34 | 40 |
| 35 std::string FormatArgumentString(const std::string& name, | 41 std::string FormatArgumentString(const std::string& name, |
| 36 const std::string& value) { | 42 const std::string& value) { |
| 37 return base::StringPrintf("--%s=%s", name.c_str(), value.c_str()); | 43 return base::StringPrintf("--%s=%s", name.c_str(), value.c_str()); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 72 // so AND them with ExcMaskValid(). EXC_MASK_CRASH is always supported. | 78 // so AND them with ExcMaskValid(). EXC_MASK_CRASH is always supported. |
| 73 bool SetCrashExceptionPorts(exception_handler_t exception_handler) { | 79 bool SetCrashExceptionPorts(exception_handler_t exception_handler) { |
| 74 ExceptionPorts exception_ports(ExceptionPorts::kTargetTypeTask, TASK_NULL); | 80 ExceptionPorts exception_ports(ExceptionPorts::kTargetTypeTask, TASK_NULL); |
| 75 return exception_ports.SetExceptionPort( | 81 return exception_ports.SetExceptionPort( |
| 76 (EXC_MASK_CRASH | EXC_MASK_RESOURCE | EXC_MASK_GUARD) & ExcMaskValid(), | 82 (EXC_MASK_CRASH | EXC_MASK_RESOURCE | EXC_MASK_GUARD) & ExcMaskValid(), |
| 77 exception_handler, | 83 exception_handler, |
| 78 EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, | 84 EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, |
| 79 MACHINE_THREAD_STATE); | 85 MACHINE_THREAD_STATE); |
| 80 } | 86 } |
| 81 | 87 |
| 82 //! \brief Starts a Crashpad handler. | 88 class ScopedPthreadAttrDestroy { |
| 83 class HandlerStarter final { | |
| 84 public: | 89 public: |
| 85 //! \brief Starts a Crashpad handler. | 90 explicit ScopedPthreadAttrDestroy(pthread_attr_t* pthread_attr) |
| 91 : pthread_attr_(pthread_attr) { | |
| 92 } | |
| 93 | |
| 94 ~ScopedPthreadAttrDestroy() { | |
| 95 errno = pthread_attr_destroy(pthread_attr_); | |
| 96 PLOG_IF(WARNING, errno != 0) << "pthread_attr_destroy"; | |
| 97 } | |
| 98 | |
| 99 private: | |
| 100 pthread_attr_t* pthread_attr_; | |
| 101 | |
| 102 DISALLOW_COPY_AND_ASSIGN(ScopedPthreadAttrDestroy); | |
| 103 }; | |
| 104 | |
| 105 //! \brief Starts a Crashpad handler, possibly restarting it if it dies. | |
| 106 class HandlerStarter final : public NotifyServer::DefaultInterface { | |
| 107 public: | |
| 108 ~HandlerStarter() {} | |
| 109 | |
| 110 //! \brief Starts a Crashpad handler initially, as opposed to starting it for | |
| 111 //! subsequent restarts. | |
| 86 //! | 112 //! |
| 87 //! All parameters are as in CrashpadClient::StartHandler(). | 113 //! All parameters are as in CrashpadClient::StartHandler(). |
| 88 //! | 114 //! |
| 89 //! \return On success, a send right to the Crashpad handler that has been | 115 //! \return On success, a send right to the Crashpad handler that has been |
| 90 //! started. On failure, `MACH_PORT_NULL` with a message logged. | 116 //! started. On failure, `MACH_PORT_NULL` with a message logged. |
| 91 static base::mac::ScopedMachSendRight Start( | 117 static base::mac::ScopedMachSendRight InitialStart( |
| 92 const base::FilePath& handler, | 118 const base::FilePath& handler, |
| 93 const base::FilePath& database, | 119 const base::FilePath& database, |
| 94 const std::string& url, | 120 const std::string& url, |
| 95 const std::map<std::string, std::string>& annotations, | 121 const std::map<std::string, std::string>& annotations, |
| 96 const std::vector<std::string>& arguments) { | 122 const std::vector<std::string>& arguments, |
| 123 bool restartable) { | |
| 97 base::mac::ScopedMachReceiveRight receive_right( | 124 base::mac::ScopedMachReceiveRight receive_right( |
| 98 NewMachPort(MACH_PORT_RIGHT_RECEIVE)); | 125 NewMachPort(MACH_PORT_RIGHT_RECEIVE)); |
| 99 if (receive_right == kMachPortNull) { | 126 if (receive_right == kMachPortNull) { |
| 100 return base::mac::ScopedMachSendRight(); | 127 return base::mac::ScopedMachSendRight(); |
| 101 } | 128 } |
| 102 | 129 |
| 103 mach_port_t port; | 130 mach_port_t port; |
| 104 mach_msg_type_name_t right_type; | 131 mach_msg_type_name_t right_type; |
| 105 kern_return_t kr = mach_port_extract_right(mach_task_self(), | 132 kern_return_t kr = mach_port_extract_right(mach_task_self(), |
| 106 receive_right.get(), | 133 receive_right.get(), |
| 107 MACH_MSG_TYPE_MAKE_SEND, | 134 MACH_MSG_TYPE_MAKE_SEND, |
| 108 &port, | 135 &port, |
| 109 &right_type); | 136 &right_type); |
| 110 if (kr != KERN_SUCCESS) { | 137 if (kr != KERN_SUCCESS) { |
| 111 MACH_LOG(ERROR, kr) << "mach_port_extract_right"; | 138 MACH_LOG(ERROR, kr) << "mach_port_extract_right"; |
| 112 return base::mac::ScopedMachSendRight(); | 139 return base::mac::ScopedMachSendRight(); |
| 113 } | 140 } |
| 114 base::mac::ScopedMachSendRight send_right(port); | 141 base::mac::ScopedMachSendRight send_right(port); |
| 115 DCHECK_EQ(port, receive_right.get()); | 142 DCHECK_EQ(port, receive_right.get()); |
| 116 DCHECK_EQ(right_type, | 143 DCHECK_EQ(right_type, |
| 117 implicit_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND)); | 144 implicit_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND)); |
| 118 | 145 |
| 146 scoped_ptr<HandlerStarter> handler_starter; | |
|
Robert Sesek
2015/11/03 15:50:27
handler_restarter ?
| |
| 147 if (restartable) { | |
| 148 handler_starter.reset(new HandlerStarter()); | |
| 149 if (handler_starter->notify_port_ == kMachPortNull) { | |
|
Robert Sesek
2015/11/03 15:50:27
Leave a comment here indicating that this is an er
| |
| 150 handler_starter.reset(); | |
| 151 } | |
| 152 } | |
| 153 | |
| 119 if (!CommonStart(handler, | 154 if (!CommonStart(handler, |
| 120 database, | 155 database, |
| 121 url, | 156 url, |
| 122 annotations, | 157 annotations, |
| 123 arguments, | 158 arguments, |
| 124 receive_right.Pass())) { | 159 receive_right.Pass(), |
| 160 handler_starter.get(), | |
| 161 false)) { | |
| 125 return base::mac::ScopedMachSendRight(); | 162 return base::mac::ScopedMachSendRight(); |
| 126 } | 163 } |
| 127 | 164 |
| 165 if (handler_starter && handler_starter->StartRestartThread( | |
| 166 handler, database, url, annotations, arguments)) { | |
| 167 // The thread owns the object now. | |
| 168 ignore_result(handler_starter.release()); | |
| 169 } | |
| 170 | |
| 128 return send_right; | 171 return send_right; |
| 129 } | 172 } |
| 130 | 173 |
| 174 // NotifyServer::DefaultInterface: | |
| 175 | |
| 176 kern_return_t DoMachNotifyPortDestroyed(notify_port_t notify, | |
| 177 mach_port_t rights, | |
| 178 const mach_msg_trailer_t* trailer, | |
| 179 bool* destroy_request) override { | |
| 180 // The receive right corresponding to this process’ crash exception port is | |
| 181 // now owned by this process. Any crashes that occur before the receive | |
| 182 // right is moved to a new handler process will cause the process to hang in | |
| 183 // an unkillable state prior to OS X 10.10. | |
| 184 | |
| 185 if (notify != notify_port_) { | |
| 186 LOG(WARNING) << "notify port mismatch"; | |
| 187 return KERN_FAILURE; | |
| 188 } | |
| 189 | |
| 190 // If CommonStart() fails, the receive right will die, and this will just | |
| 191 // be called again for another try. | |
| 192 CommonStart(handler_, | |
| 193 database_, | |
| 194 url_, | |
| 195 annotations_, | |
| 196 arguments_, | |
| 197 base::mac::ScopedMachReceiveRight(rights), | |
| 198 this, | |
| 199 true); | |
| 200 | |
| 201 return KERN_SUCCESS; | |
| 202 } | |
| 203 | |
| 131 private: | 204 private: |
| 205 HandlerStarter() | |
| 206 : NotifyServer::DefaultInterface(), | |
| 207 handler_(), | |
| 208 database_(), | |
| 209 url_(), | |
| 210 annotations_(), | |
| 211 arguments_(), | |
| 212 notify_port_(NewMachPort(MACH_PORT_RIGHT_RECEIVE)), | |
| 213 last_start_time_(0) { | |
| 214 } | |
| 215 | |
| 216 //! \brief Starts a Crashpad handler. | |
| 217 //! | |
| 218 //! All parameters are as in CrashpadClient::StartHandler(), with these | |
| 219 //! additions: | |
| 220 //! | |
| 221 //! \param[in] receive_right The receive right to move to the Crashpad | |
| 222 //! handler. The handler will use this receive right to run its exception | |
| 223 //! server. | |
| 224 //! \param[in] handler_starter If CrashpadClient::StartHandler() was invoked | |
| 225 //! with \a restartable set to `true`, this is the restart state object. | |
| 226 //! Otherwise, this is `nullptr`. | |
| 227 //! \param[in] restart If CrashpadClient::StartHandler() was invoked with \a | |
| 228 //! restartable set to `true` and CommonStart() is being called to restart | |
| 229 //! a previously-started handler, this is `true`. Otherwise, this is | |
| 230 //! `false`. | |
| 231 //! | |
| 232 //! \return `true` on success, `false` on failure, with a message logged. | |
| 233 //! Failures include failure to start the handler process and failure to | |
| 234 //! rendezvous with it via ChildPortHandshake. | |
| 132 static bool CommonStart(const base::FilePath& handler, | 235 static bool CommonStart(const base::FilePath& handler, |
| 133 const base::FilePath& database, | 236 const base::FilePath& database, |
| 134 const std::string& url, | 237 const std::string& url, |
| 135 const std::map<std::string, std::string>& annotations, | 238 const std::map<std::string, std::string>& annotations, |
| 136 const std::vector<std::string>& arguments, | 239 const std::vector<std::string>& arguments, |
| 137 base::mac::ScopedMachReceiveRight receive_right) { | 240 base::mac::ScopedMachReceiveRight receive_right, |
| 241 HandlerStarter* handler_starter, | |
| 242 bool restart) { | |
| 243 if (handler_starter) { | |
| 244 // The port-destroyed notification must be requested each time. It uses | |
| 245 // a send-once right, so once the notification is received, it won’t be | |
| 246 // sent again unless re-requested. | |
| 247 mach_port_t previous; | |
| 248 kern_return_t kr = | |
| 249 mach_port_request_notification(mach_task_self(), | |
| 250 receive_right.get(), | |
| 251 MACH_NOTIFY_PORT_DESTROYED, | |
| 252 0, | |
| 253 handler_starter->notify_port_.get(), | |
| 254 MACH_MSG_TYPE_MAKE_SEND_ONCE, | |
| 255 &previous); | |
| 256 if (kr != KERN_SUCCESS) { | |
| 257 MACH_LOG(WARNING, kr) << "mach_port_request_notification"; | |
| 258 | |
| 259 // This will cause the restart thread to terminate after this restart | |
| 260 // attempt. There’s no longer any need for it, because no more | |
| 261 // port-destroyed notifications can be delivered. | |
| 262 handler_starter->notify_port_.reset(); | |
| 263 } else { | |
| 264 base::mac::ScopedMachSendRight previous_owner(previous); | |
| 265 if (!restart) { | |
| 266 DCHECK_EQ(previous, kMachPortNull); | |
| 267 } | |
| 268 } | |
| 269 | |
| 270 if (handler_starter->last_start_time_) { | |
| 271 // If the handler was ever started before, don’t restart it too quickly. | |
| 272 const uint64_t kNanosecondsPerSecond = 1E9; | |
| 273 const uint64_t kMinimumStartInterval = 1 * kNanosecondsPerSecond; | |
| 274 | |
| 275 const uint64_t earliest_next_start_time = | |
| 276 handler_starter->last_start_time_ + kMinimumStartInterval; | |
| 277 const uint64_t now_time = ClockMonotonicNanoseconds(); | |
| 278 if (earliest_next_start_time > now_time) { | |
| 279 SleepNanoseconds(earliest_next_start_time - now_time); | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 handler_starter->last_start_time_ = ClockMonotonicNanoseconds(); | |
| 284 } | |
| 285 | |
| 138 // Set up the arguments for execve() first. These aren’t needed until | 286 // Set up the arguments for execve() first. These aren’t needed until |
| 139 // execve() is called, but it’s dangerous to do this in a child process | 287 // execve() is called, but it’s dangerous to do this in a child process |
| 140 // after fork(). | 288 // after fork(). |
| 141 ChildPortHandshake child_port_handshake; | 289 ChildPortHandshake child_port_handshake; |
| 142 base::ScopedFD server_write_fd = child_port_handshake.ServerWriteFD(); | 290 base::ScopedFD server_write_fd = child_port_handshake.ServerWriteFD(); |
| 143 | 291 |
| 144 // Use handler as argv[0], followed by arguments directed by this method’s | 292 // Use handler as argv[0], followed by arguments directed by this method’s |
| 145 // parameters and a --handshake-fd argument. |arguments| are added first so | 293 // parameters and a --handshake-fd argument. |arguments| are added first so |
| 146 // that if it erroneously contains an argument such as --url, the actual | 294 // that if it erroneously contains an argument such as --url, the actual |
| 147 // |url| argument passed to this method will supersede it. In normal | 295 // |url| argument passed to this method will supersede it. In normal |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 188 // process will not result in a zombie process. | 336 // process will not result in a zombie process. |
| 189 pid_t pid = fork(); | 337 pid_t pid = fork(); |
| 190 if (pid < 0) { | 338 if (pid < 0) { |
| 191 PLOG(ERROR) << "fork"; | 339 PLOG(ERROR) << "fork"; |
| 192 return false; | 340 return false; |
| 193 } | 341 } |
| 194 | 342 |
| 195 if (pid == 0) { | 343 if (pid == 0) { |
| 196 // Child process. | 344 // Child process. |
| 197 | 345 |
| 346 if (restart) { | |
| 347 // When restarting, reset the system default crash handler first. | |
| 348 // Otherwise, the crash exception port here will have been inherited | |
| 349 // from the parent process, which was probably using the exception | |
| 350 // server now being restarted. The handler can’t monitor itself for its | |
| 351 // own crashes via this interface. | |
| 352 CrashpadClient::UseSystemDefaultHandler(); | |
| 353 } | |
| 354 | |
| 198 // Call setsid(), creating a new process group and a new session, both led | 355 // Call setsid(), creating a new process group and a new session, both led |
| 199 // by this process. The new process group has no controlling terminal. | 356 // by this process. The new process group has no controlling terminal. |
| 200 // This disconnects it from signals generated by the parent process’ | 357 // This disconnects it from signals generated by the parent process’ |
| 201 // terminal. | 358 // terminal. |
| 202 // | 359 // |
| 203 // setsid() is done in the child instead of the grandchild so that the | 360 // setsid() is done in the child instead of the grandchild so that the |
| 204 // grandchild will not be a session leader. If it were a session leader, | 361 // grandchild will not be a session leader. If it were a session leader, |
| 205 // an accidental open() of a terminal device without O_NOCTTY would make | 362 // an accidental open() of a terminal device without O_NOCTTY would make |
| 206 // that terminal the controlling terminal. | 363 // that terminal the controlling terminal. |
| 207 // | 364 // |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 262 // Rendezvous with the handler running in the grandchild process. | 419 // Rendezvous with the handler running in the grandchild process. |
| 263 if (!child_port_handshake.RunClient(receive_right.get(), | 420 if (!child_port_handshake.RunClient(receive_right.get(), |
| 264 MACH_MSG_TYPE_MOVE_RECEIVE)) { | 421 MACH_MSG_TYPE_MOVE_RECEIVE)) { |
| 265 return false; | 422 return false; |
| 266 } | 423 } |
| 267 | 424 |
| 268 ignore_result(receive_right.release()); | 425 ignore_result(receive_right.release()); |
| 269 return true; | 426 return true; |
| 270 } | 427 } |
| 271 | 428 |
| 272 DISALLOW_IMPLICIT_CONSTRUCTORS(HandlerStarter); | 429 bool StartRestartThread(const base::FilePath& handler, |
| 430 const base::FilePath& database, | |
| 431 const std::string& url, | |
| 432 const std::map<std::string, std::string>& annotations, | |
| 433 const std::vector<std::string>& arguments) { | |
| 434 handler_ = handler; | |
| 435 database_ = database; | |
| 436 url_ = url; | |
| 437 annotations_ = annotations; | |
| 438 arguments_ = arguments; | |
| 439 | |
| 440 pthread_attr_t pthread_attr; | |
| 441 errno = pthread_attr_init(&pthread_attr); | |
| 442 if (errno != 0) { | |
| 443 PLOG(WARNING) << "pthread_attr_init"; | |
| 444 return false; | |
| 445 } | |
| 446 ScopedPthreadAttrDestroy pthread_attr_owner(&pthread_attr); | |
| 447 | |
| 448 errno = pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_DETACHED); | |
| 449 if (errno != 0) { | |
| 450 PLOG(WARNING) << "pthread_attr_setdetachstate"; | |
| 451 return false; | |
| 452 } | |
| 453 | |
| 454 pthread_t pthread; | |
| 455 errno = pthread_create(&pthread, &pthread_attr, RestartThreadMain, this); | |
| 456 if (errno != 0) { | |
| 457 PLOG(WARNING) << "pthread_create"; | |
| 458 return false; | |
| 459 } | |
| 460 | |
| 461 return true; | |
| 462 } | |
| 463 | |
| 464 static void* RestartThreadMain(void* argument) { | |
| 465 HandlerStarter* self = reinterpret_cast<HandlerStarter*>(argument); | |
| 466 | |
| 467 NotifyServer notify_server(self); | |
| 468 mach_msg_return_t mr; | |
| 469 do { | |
| 470 mr = MachMessageServer::Run(¬ify_server, | |
| 471 self->notify_port_.get(), | |
| 472 0, | |
| 473 MachMessageServer::kPersistent, | |
| 474 MachMessageServer::kReceiveLargeError, | |
| 475 kMachMessageTimeoutWaitIndefinitely); | |
| 476 MACH_LOG_IF(ERROR, mr != MACH_MSG_SUCCESS, mr) | |
| 477 << "MachMessageServer::Run"; | |
| 478 } while (self->notify_port_ != kMachPortNull && mr == MACH_MSG_SUCCESS); | |
| 479 | |
| 480 delete self; | |
| 481 | |
| 482 return nullptr; | |
| 483 } | |
| 484 | |
| 485 base::FilePath handler_; | |
| 486 base::FilePath database_; | |
| 487 std::string url_; | |
| 488 std::map<std::string, std::string> annotations_; | |
| 489 std::vector<std::string> arguments_; | |
| 490 base::mac::ScopedMachReceiveRight notify_port_; | |
| 491 uint64_t last_start_time_; | |
| 492 | |
| 493 DISALLOW_COPY_AND_ASSIGN(HandlerStarter); | |
| 273 }; | 494 }; |
| 274 | 495 |
| 275 } // namespace | 496 } // namespace |
| 276 | 497 |
| 277 CrashpadClient::CrashpadClient() | 498 CrashpadClient::CrashpadClient() |
| 278 : exception_port_() { | 499 : exception_port_() { |
| 279 } | 500 } |
| 280 | 501 |
| 281 CrashpadClient::~CrashpadClient() { | 502 CrashpadClient::~CrashpadClient() { |
| 282 } | 503 } |
| 283 | 504 |
| 284 bool CrashpadClient::StartHandler( | 505 bool CrashpadClient::StartHandler( |
| 285 const base::FilePath& handler, | 506 const base::FilePath& handler, |
| 286 const base::FilePath& database, | 507 const base::FilePath& database, |
| 287 const std::string& url, | 508 const std::string& url, |
| 288 const std::map<std::string, std::string>& annotations, | 509 const std::map<std::string, std::string>& annotations, |
| 289 const std::vector<std::string>& arguments) { | 510 const std::vector<std::string>& arguments, |
| 511 bool restartable) { | |
| 290 DCHECK(!exception_port_.is_valid()); | 512 DCHECK(!exception_port_.is_valid()); |
| 291 | 513 |
| 292 exception_port_ = HandlerStarter::Start( | 514 // The “restartable” behavior can only be selected on OS X 10.10 and later. In |
| 293 handler, database, url, annotations, arguments); | 515 // previous OS versions, if the initial client were to crash while attempting |
| 516 // to restart the handler, it would become an unkillable process. | |
| 517 exception_port_ = HandlerStarter::InitialStart( | |
| 518 handler, | |
| 519 database, | |
| 520 url, | |
| 521 annotations, | |
| 522 arguments, | |
| 523 restartable && MacOSXMinorVersion() >= 10); | |
| 294 if (!exception_port_.is_valid()) { | 524 if (!exception_port_.is_valid()) { |
| 295 return false; | 525 return false; |
| 296 } | 526 } |
| 297 | 527 |
| 298 return true; | 528 return true; |
| 299 } | 529 } |
| 300 | 530 |
| 301 bool CrashpadClient::UseHandler() { | 531 bool CrashpadClient::UseHandler() { |
| 302 DCHECK(exception_port_.is_valid()); | 532 DCHECK(exception_port_.is_valid()); |
| 303 | 533 |
| 304 return SetCrashExceptionPorts(exception_port_.get()); | 534 return SetCrashExceptionPorts(exception_port_.get()); |
| 305 } | 535 } |
| 306 | 536 |
| 307 // static | 537 // static |
| 308 void CrashpadClient::UseSystemDefaultHandler() { | 538 void CrashpadClient::UseSystemDefaultHandler() { |
| 309 base::mac::ScopedMachSendRight | 539 base::mac::ScopedMachSendRight |
| 310 system_crash_reporter_handler(SystemCrashReporterHandler()); | 540 system_crash_reporter_handler(SystemCrashReporterHandler()); |
| 311 | 541 |
| 312 // Proceed even if SystemCrashReporterHandler() failed, setting MACH_PORT_NULL | 542 // Proceed even if SystemCrashReporterHandler() failed, setting MACH_PORT_NULL |
| 313 // to clear the current exception ports. | 543 // to clear the current exception ports. |
| 314 if (!SetCrashExceptionPorts(system_crash_reporter_handler.get())) { | 544 if (!SetCrashExceptionPorts(system_crash_reporter_handler.get())) { |
| 315 SetCrashExceptionPorts(MACH_PORT_NULL); | 545 SetCrashExceptionPorts(MACH_PORT_NULL); |
| 316 } | 546 } |
| 317 } | 547 } |
| 318 | 548 |
| 319 } // namespace crashpad | 549 } // namespace crashpad |
| OLD | NEW |