1eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// Copyright (c) 2008, Google Inc.
2eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// All rights reserved.
3eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai//
4eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// Redistribution and use in source and binary forms, with or without
5eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// modification, are permitted provided that the following conditions are
6eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// met:
7eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai//
8eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai//     * Redistributions of source code must retain the above copyright
9eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// notice, this list of conditions and the following disclaimer.
10eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai//     * Redistributions in binary form must reproduce the above
11eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// copyright notice, this list of conditions and the following disclaimer
12eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// in the documentation and/or other materials provided with the
13eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// distribution.
14eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai//     * Neither the name of Google Inc. nor the names of its
15eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// contributors may be used to endorse or promote products derived from
16eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// this software without specific prior written permission.
17eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai//
18eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
30eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai#include "client/windows/crash_generation/client_info.h"
310ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun#include "client/windows/common/ipc_protocol.h"
32eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
333a516e41775099eb27533e7d2b3178c5f353a3a8doshimunstatic const wchar_t kCustomInfoProcessUptimeName[] = L"ptime";
3414ec03a395dc6b0c9784e0e86ff4574cbe3d3795cdn@chromium.orgstatic const size_t kMaxCustomInfoEntries = 4096;
353a516e41775099eb27533e7d2b3178c5f353a3a8doshimun
36eeca9921c563d802cccc5593bf55dcb7683e7250mmentovainamespace google_breakpad {
37eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
38eeca9921c563d802cccc5593bf55dcb7683e7250mmentovaiClientInfo::ClientInfo(CrashGenerationServer* crash_server,
39eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                       DWORD pid,
40eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                       MINIDUMP_TYPE dump_type,
41eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                       DWORD* thread_id,
42eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                       EXCEPTION_POINTERS** ex_info,
430ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun                       MDRawAssertionInfo* assert_info,
440ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun                       const CustomClientInfo& custom_client_info)
45eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai    : crash_server_(crash_server),
46eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai      pid_(pid),
47eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai      dump_type_(dump_type),
48eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai      ex_info_(ex_info),
49eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai      assert_info_(assert_info),
500ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun      custom_client_info_(custom_client_info),
51eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai      thread_id_(thread_id),
52eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai      process_handle_(NULL),
53eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai      dump_requested_handle_(NULL),
54eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai      dump_generated_handle_(NULL),
55eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai      dump_request_wait_handle_(NULL),
56eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org      process_exit_wait_handle_(NULL),
57eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org      crash_id_(NULL) {
583a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  GetSystemTimeAsFileTime(&start_time_);
59eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai}
60eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
61eeca9921c563d802cccc5593bf55dcb7683e7250mmentovaibool ClientInfo::Initialize() {
6272bafd378d836d9a1fe81a1f26c91d51b2a7892bdoshimun  process_handle_ = OpenProcess(GENERIC_ALL, FALSE, pid_);
63eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  if (!process_handle_) {
64eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai    return false;
65eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  }
66eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
67eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org  // The crash_id will be the low order word of the process creation time.
68eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org  FILETIME creation_time, exit_time, kernel_time, user_time;
69eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org  if (GetProcessTimes(process_handle_, &creation_time, &exit_time,
706afe338f2355bf1bbe4b8f869aeb16b093ae2ab2ivanpe@chromium.org                      &kernel_time, &user_time)) {
716afe338f2355bf1bbe4b8f869aeb16b093ae2ab2ivanpe@chromium.org    start_time_ = creation_time;
726afe338f2355bf1bbe4b8f869aeb16b093ae2ab2ivanpe@chromium.org  }
736afe338f2355bf1bbe4b8f869aeb16b093ae2ab2ivanpe@chromium.org  crash_id_ = start_time_.dwLowDateTime;
74eb991531e31b7c001200cf23ce07efc5a32b41aecdn@chromium.org
75eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  dump_requested_handle_ = CreateEvent(NULL,    // Security attributes.
76eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                                       TRUE,    // Manual reset.
77eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                                       FALSE,   // Initial state.
78eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                                       NULL);   // Name.
79eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  if (!dump_requested_handle_) {
80eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai    return false;
81eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  }
82eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
83eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  dump_generated_handle_ = CreateEvent(NULL,    // Security attributes.
84eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                                       TRUE,    // Manual reset.
85eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                                       FALSE,   // Initial state.
86eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                                       NULL);   // Name.
87eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  return dump_generated_handle_ != NULL;
88eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai}
89eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
9055cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.comvoid ClientInfo::UnregisterDumpRequestWaitAndBlockUntilNoPending() {
912d7664e8d477816e0641e822752f63982c1be74fdoshimun  if (dump_request_wait_handle_) {
922d7664e8d477816e0641e822752f63982c1be74fdoshimun    // Wait for callbacks that might already be running to finish.
932d7664e8d477816e0641e822752f63982c1be74fdoshimun    UnregisterWaitEx(dump_request_wait_handle_, INVALID_HANDLE_VALUE);
9455cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com    dump_request_wait_handle_ = NULL;
952d7664e8d477816e0641e822752f63982c1be74fdoshimun  }
9655cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com}
972d7664e8d477816e0641e822752f63982c1be74fdoshimun
9855cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.comvoid ClientInfo::UnregisterProcessExitWait(bool block_until_no_pending) {
992d7664e8d477816e0641e822752f63982c1be74fdoshimun  if (process_exit_wait_handle_) {
10055cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com    if (block_until_no_pending) {
10155cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com      // Wait for the callback that might already be running to finish.
10255cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com      UnregisterWaitEx(process_exit_wait_handle_, INVALID_HANDLE_VALUE);
10355cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com    } else {
10455cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com      UnregisterWait(process_exit_wait_handle_);
10555cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com    }
10655cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com    process_exit_wait_handle_ = NULL;
1072d7664e8d477816e0641e822752f63982c1be74fdoshimun  }
10855cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com}
10955cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com
11055cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.comClientInfo::~ClientInfo() {
11155cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com  // Waiting for the callback to finish here is safe because ClientInfo's are
11255cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com  // never destroyed from the dump request handling callback.
11355cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com  UnregisterDumpRequestWaitAndBlockUntilNoPending();
11455cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com
11555cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com  // This is a little tricky because ClientInfo's may be destroyed by the same
11655cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com  // callback (OnClientEnd) and waiting for it to finish will cause a deadlock.
11755cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com  // Regardless of this complication, wait for any running callbacks to finish
11855cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com  // so that the common case is properly handled.  In order to avoid deadlocks,
11955cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com  // the OnClientEnd callback must call UnregisterProcessExitWait(false)
12055cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com  // before deleting the ClientInfo.
12155cc396a9f783213f6033a6f4e12d56d47af40a5ivan.penkov@gmail.com  UnregisterProcessExitWait(true);
1222d7664e8d477816e0641e822752f63982c1be74fdoshimun
123eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  if (process_handle_) {
124eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai    CloseHandle(process_handle_);
125eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  }
126eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
127eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  if (dump_requested_handle_) {
128eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai    CloseHandle(dump_requested_handle_);
129eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  }
130eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
131eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  if (dump_generated_handle_) {
132eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai    CloseHandle(dump_generated_handle_);
133eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  }
134eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai}
135eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
1360ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimunbool ClientInfo::GetClientExceptionInfo(EXCEPTION_POINTERS** ex_info) const {
137eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  SIZE_T bytes_count = 0;
138eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  if (!ReadProcessMemory(process_handle_,
139eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                         ex_info_,
140eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                         ex_info,
141eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                         sizeof(*ex_info),
142eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                         &bytes_count)) {
143eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai    return false;
144eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  }
145eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
146eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  return bytes_count == sizeof(*ex_info);
147eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai}
148eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
149eeca9921c563d802cccc5593bf55dcb7683e7250mmentovaibool ClientInfo::GetClientThreadId(DWORD* thread_id) const {
150eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  SIZE_T bytes_count = 0;
151eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  if (!ReadProcessMemory(process_handle_,
152eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                         thread_id_,
153eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                         thread_id,
154eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                         sizeof(*thread_id),
155eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai                         &bytes_count)) {
156eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai    return false;
157eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  }
158eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
159eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai  return bytes_count == sizeof(*thread_id);
160eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai}
161eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai
1623a516e41775099eb27533e7d2b3178c5f353a3a8doshimunvoid ClientInfo::SetProcessUptime() {
1633a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  FILETIME now = {0};
1643a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  GetSystemTimeAsFileTime(&now);
1653a516e41775099eb27533e7d2b3178c5f353a3a8doshimun
1663a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  ULARGE_INTEGER time_start;
1673a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  time_start.HighPart = start_time_.dwHighDateTime;
1683a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  time_start.LowPart = start_time_.dwLowDateTime;
1693a516e41775099eb27533e7d2b3178c5f353a3a8doshimun
1703a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  ULARGE_INTEGER time_now;
1713a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  time_now.HighPart = now.dwHighDateTime;
1723a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  time_now.LowPart = now.dwLowDateTime;
1733a516e41775099eb27533e7d2b3178c5f353a3a8doshimun
1743a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  // Calculate the delay and convert it from 100-nanoseconds to milliseconds.
1753a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  __int64 delay = (time_now.QuadPart - time_start.QuadPart) / 10 / 1000;
1763a516e41775099eb27533e7d2b3178c5f353a3a8doshimun
1773a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  // Convert it to a string.
1783a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  wchar_t* value = custom_info_entries_.get()[custom_client_info_.count].value;
1793a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  _i64tow_s(delay, value, CustomInfoEntry::kValueMaxLength, 10);
1803a516e41775099eb27533e7d2b3178c5f353a3a8doshimun}
1813a516e41775099eb27533e7d2b3178c5f353a3a8doshimun
1820ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimunbool ClientInfo::PopulateCustomInfo() {
18314ec03a395dc6b0c9784e0e86ff4574cbe3d3795cdn@chromium.org  if (custom_client_info_.count > kMaxCustomInfoEntries)
18414ec03a395dc6b0c9784e0e86ff4574cbe3d3795cdn@chromium.org    return false;
18514ec03a395dc6b0c9784e0e86ff4574cbe3d3795cdn@chromium.org
1860ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun  SIZE_T bytes_count = 0;
1870ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun  SIZE_T read_count = sizeof(CustomInfoEntry) * custom_client_info_.count;
1880ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun
1890ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun  // If the scoped array for custom info already has an array, it will be
1900ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun  // the same size as what we need. This is because the number of custom info
1910ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun  // entries is always the same. So allocate memory only if scoped array has
1920ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun  // a NULL pointer.
1930ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun  if (!custom_info_entries_.get()) {
1943a516e41775099eb27533e7d2b3178c5f353a3a8doshimun    // Allocate an extra entry for reporting uptime for the client process.
1953a516e41775099eb27533e7d2b3178c5f353a3a8doshimun    custom_info_entries_.reset(
1963a516e41775099eb27533e7d2b3178c5f353a3a8doshimun        new CustomInfoEntry[custom_client_info_.count + 1]);
1973a516e41775099eb27533e7d2b3178c5f353a3a8doshimun    // Use the last element in the array for uptime.
1983a516e41775099eb27533e7d2b3178c5f353a3a8doshimun    custom_info_entries_.get()[custom_client_info_.count].set_name(
1993a516e41775099eb27533e7d2b3178c5f353a3a8doshimun        kCustomInfoProcessUptimeName);
2000ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun  }
2010ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun
2020ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun  if (!ReadProcessMemory(process_handle_,
2030ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun                         custom_client_info_.entries,
2040ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun                         custom_info_entries_.get(),
2050ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun                         read_count,
2060ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun                         &bytes_count)) {
2070ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun    return false;
2080ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun  }
2090ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun
2103a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  SetProcessUptime();
211c20745c254b0934520c5c45de9fdf0c4cbce54fdivan.penkov@gmail.com  return (bytes_count == read_count);
2120ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun}
2130ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun
2147ab126ecdd5237ccd566f415cc560b39f87e8a0fdoshimunCustomClientInfo ClientInfo::GetCustomInfo() const {
2157ab126ecdd5237ccd566f415cc560b39f87e8a0fdoshimun  CustomClientInfo custom_info;
2167ab126ecdd5237ccd566f415cc560b39f87e8a0fdoshimun  custom_info.entries = custom_info_entries_.get();
2173a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  // Add 1 to the count from the client process to account for extra entry for
2183a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  // process uptime.
2193a516e41775099eb27533e7d2b3178c5f353a3a8doshimun  custom_info.count = custom_client_info_.count + 1;
2207ab126ecdd5237ccd566f415cc560b39f87e8a0fdoshimun  return custom_info;
2210ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun}
2220ded3d718f4b090d106014bb0ea9dbb7af4e1d81doshimun
223eeca9921c563d802cccc5593bf55dcb7683e7250mmentovai}  // namespace google_breakpad
224