1 // Copyright (c) 2012 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.
5 #include "ipc/ipc_message.h"
9 #include "base/atomic_sequence_num.h"
10 #include "base/logging.h"
11 #include "build/build_config.h"
12 #include "ipc/ipc_message_attachment.h"
13 #include "ipc/ipc_message_attachment_set.h"
16 #include "base/file_descriptor_posix.h"
17 #include "ipc/ipc_platform_file_attachment_posix.h"
22 base::StaticAtomicSequenceNumber g_ref_num
;
24 // Create a reference number for identifying IPC messages in traces. The return
25 // values has the reference number stored in the upper 24 bits, leaving the low
26 // 8 bits set to 0 for use as flags.
27 inline uint32_t GetRefNumUpper24() {
28 base::trace_event::TraceLog
* trace_log
=
29 base::trace_event::TraceLog::GetInstance();
30 uint32_t pid
= trace_log
? trace_log
->process_id() : 0;
31 uint32_t count
= g_ref_num
.GetNext();
32 // The 24 bit hash is composed of 14 bits of the count and 10 bits of the
33 // Process ID. With the current trace event buffer cap, the 14-bit count did
34 // not appear to wrap during a trace. Note that it is not a big deal if
35 // collisions occur, as this is only used for debugging and trace analysis.
36 return ((pid
<< 14) | (count
& 0x3fff)) << 8;
43 //------------------------------------------------------------------------------
48 Message::Message() : base::Pickle(sizeof(Header
)) {
49 header()->routing
= header()->type
= 0;
50 header()->flags
= GetRefNumUpper24();
52 header()->num_fds
= 0;
58 Message::Message(int32_t routing_id
, uint32_t type
, PriorityValue priority
)
59 : base::Pickle(sizeof(Header
)) {
60 header()->routing
= routing_id
;
61 header()->type
= type
;
62 DCHECK((priority
& 0xffffff00) == 0);
63 header()->flags
= priority
| GetRefNumUpper24();
65 header()->num_fds
= 0;
71 Message::Message(const char* data
, int data_len
)
72 : base::Pickle(data
, data_len
) {
76 Message::Message(const Message
& other
) : base::Pickle(other
) {
78 attachment_set_
= other
.attachment_set_
;
81 void Message::Init() {
82 dispatch_error_
= false;
83 sender_pid_
= base::kNullProcessId
;
84 #ifdef IPC_MESSAGE_LOG_ENABLED
91 Message
& Message::operator=(const Message
& other
) {
92 *static_cast<base::Pickle
*>(this) = other
;
93 attachment_set_
= other
.attachment_set_
;
97 void Message::SetHeaderValues(int32_t routing
, uint32_t type
, uint32_t flags
) {
98 // This should only be called when the message is already empty.
99 DCHECK(payload_size() == 0);
101 header()->routing
= routing
;
102 header()->type
= type
;
103 header()->flags
= flags
;
106 void Message::EnsureMessageAttachmentSet() {
107 if (attachment_set_
.get() == NULL
)
108 attachment_set_
= new MessageAttachmentSet
;
111 #ifdef IPC_MESSAGE_LOG_ENABLED
112 void Message::set_sent_time(int64_t time
) {
113 DCHECK((header()->flags
& HAS_SENT_TIME_BIT
) == 0);
114 header()->flags
|= HAS_SENT_TIME_BIT
;
118 int64_t Message::sent_time() const {
119 if ((header()->flags
& HAS_SENT_TIME_BIT
) == 0)
122 const char* data
= end_of_payload();
123 data
-= sizeof(int64_t);
124 return *(reinterpret_cast<const int64_t*>(data
));
127 void Message::set_received_time(int64_t time
) const {
128 received_time_
= time
;
132 Message::NextMessageInfo::NextMessageInfo()
133 : message_found(false), pickle_end(nullptr), message_end(nullptr) {}
134 Message::NextMessageInfo::~NextMessageInfo() {}
137 void Message::FindNext(const char* range_start
,
138 const char* range_end
,
139 NextMessageInfo
* info
) {
141 const char* pickle_end
=
142 base::Pickle::FindNext(sizeof(Header
), range_start
, range_end
);
145 info
->pickle_end
= pickle_end
;
147 #if USE_ATTACHMENT_BROKER
148 // The data is not copied.
149 size_t pickle_len
= static_cast<size_t>(pickle_end
- range_start
);
150 Message
message(range_start
, static_cast<int>(pickle_len
));
151 int num_attachments
= message
.header()->num_brokered_attachments
;
153 // Check for possible overflows.
154 size_t max_size_t
= std::numeric_limits
<size_t>::max();
155 if (num_attachments
>= max_size_t
/ BrokerableAttachment::kNonceSize
)
158 size_t attachment_length
= num_attachments
* BrokerableAttachment::kNonceSize
;
159 if (pickle_len
> max_size_t
- attachment_length
)
162 // Check whether the range includes the attachments.
163 size_t buffer_length
= static_cast<size_t>(range_end
- range_start
);
164 if (buffer_length
< attachment_length
+ pickle_len
)
167 for (int i
= 0; i
< num_attachments
; ++i
) {
168 const char* attachment_start
=
169 pickle_end
+ i
* BrokerableAttachment::kNonceSize
;
170 BrokerableAttachment::AttachmentId
id(attachment_start
,
171 BrokerableAttachment::kNonceSize
);
172 info
->attachment_ids
.push_back(id
);
175 pickle_end
+ num_attachments
* BrokerableAttachment::kNonceSize
;
177 info
->message_end
= pickle_end
;
178 #endif // USE_ATTACHMENT_BROKER
180 info
->message_found
= true;
183 bool Message::WriteAttachment(scoped_refptr
<MessageAttachment
> attachment
) {
184 // We write the index of the descriptor so that we don't have to
185 // keep the current descriptor as extra decoding state when deserialising.
186 WriteInt(attachment_set()->size());
187 return attachment_set()->AddAttachment(attachment
);
190 bool Message::ReadAttachment(
191 base::PickleIterator
* iter
,
192 scoped_refptr
<MessageAttachment
>* attachment
) const {
193 int descriptor_index
;
194 if (!iter
->ReadInt(&descriptor_index
))
197 MessageAttachmentSet
* attachment_set
= attachment_set_
.get();
201 *attachment
= attachment_set
->GetAttachmentAt(descriptor_index
);
202 return nullptr != attachment
->get();
205 bool Message::HasAttachments() const {
206 return attachment_set_
.get() && !attachment_set_
->empty();
209 bool Message::HasMojoHandles() const {
210 return attachment_set_
.get() && attachment_set_
->num_mojo_handles() > 0;
213 bool Message::HasBrokerableAttachments() const {
214 return attachment_set_
.get() &&
215 attachment_set_
->num_brokerable_attachments() > 0;