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"
14 #include "ipc/placeholder_brokerable_attachment.h"
17 #include "base/file_descriptor_posix.h"
18 #include "ipc/ipc_platform_file_attachment_posix.h"
23 base::StaticAtomicSequenceNumber g_ref_num
;
25 // Create a reference number for identifying IPC messages in traces. The return
26 // values has the reference number stored in the upper 24 bits, leaving the low
27 // 8 bits set to 0 for use as flags.
28 inline uint32_t GetRefNumUpper24() {
29 base::trace_event::TraceLog
* trace_log
=
30 base::trace_event::TraceLog::GetInstance();
31 uint32_t pid
= trace_log
? trace_log
->process_id() : 0;
32 uint32_t count
= g_ref_num
.GetNext();
33 // The 24 bit hash is composed of 14 bits of the count and 10 bits of the
34 // Process ID. With the current trace event buffer cap, the 14-bit count did
35 // not appear to wrap during a trace. Note that it is not a big deal if
36 // collisions occur, as this is only used for debugging and trace analysis.
37 return ((pid
<< 14) | (count
& 0x3fff)) << 8;
44 //------------------------------------------------------------------------------
49 Message::Message() : base::Pickle(sizeof(Header
)) {
50 header()->routing
= header()->type
= 0;
51 header()->flags
= GetRefNumUpper24();
53 header()->num_fds
= 0;
59 Message::Message(int32_t routing_id
, uint32_t type
, PriorityValue priority
)
60 : base::Pickle(sizeof(Header
)) {
61 header()->routing
= routing_id
;
62 header()->type
= type
;
63 DCHECK((priority
& 0xffffff00) == 0);
64 header()->flags
= priority
| GetRefNumUpper24();
66 header()->num_fds
= 0;
72 Message::Message(const char* data
, int data_len
)
73 : base::Pickle(data
, data_len
) {
77 Message::Message(const Message
& other
) : base::Pickle(other
) {
79 attachment_set_
= other
.attachment_set_
;
82 void Message::Init() {
83 dispatch_error_
= false;
84 sender_pid_
= base::kNullProcessId
;
85 #ifdef IPC_MESSAGE_LOG_ENABLED
92 Message
& Message::operator=(const Message
& other
) {
93 *static_cast<base::Pickle
*>(this) = other
;
94 attachment_set_
= other
.attachment_set_
;
98 void Message::SetHeaderValues(int32_t routing
, uint32_t type
, uint32_t flags
) {
99 // This should only be called when the message is already empty.
100 DCHECK(payload_size() == 0);
102 header()->routing
= routing
;
103 header()->type
= type
;
104 header()->flags
= flags
;
107 void Message::EnsureMessageAttachmentSet() {
108 if (attachment_set_
.get() == NULL
)
109 attachment_set_
= new MessageAttachmentSet
;
112 #ifdef IPC_MESSAGE_LOG_ENABLED
113 void Message::set_sent_time(int64_t time
) {
114 DCHECK((header()->flags
& HAS_SENT_TIME_BIT
) == 0);
115 header()->flags
|= HAS_SENT_TIME_BIT
;
119 int64_t Message::sent_time() const {
120 if ((header()->flags
& HAS_SENT_TIME_BIT
) == 0)
123 const char* data
= end_of_payload();
124 data
-= sizeof(int64_t);
125 return *(reinterpret_cast<const int64_t*>(data
));
128 void Message::set_received_time(int64_t time
) const {
129 received_time_
= time
;
133 Message::NextMessageInfo::NextMessageInfo()
134 : message_found(false), pickle_end(nullptr), message_end(nullptr) {}
135 Message::NextMessageInfo::~NextMessageInfo() {}
138 void Message::FindNext(const char* range_start
,
139 const char* range_end
,
140 NextMessageInfo
* info
) {
142 const char* pickle_end
=
143 base::Pickle::FindNext(sizeof(Header
), range_start
, range_end
);
146 info
->pickle_end
= pickle_end
;
148 #if USE_ATTACHMENT_BROKER
149 // The data is not copied.
150 size_t pickle_len
= static_cast<size_t>(pickle_end
- range_start
);
151 Message
message(range_start
, static_cast<int>(pickle_len
));
152 int num_attachments
= message
.header()->num_brokered_attachments
;
154 // Check for possible overflows.
155 size_t max_size_t
= std::numeric_limits
<size_t>::max();
156 if (num_attachments
>= max_size_t
/ BrokerableAttachment::kNonceSize
)
159 size_t attachment_length
= num_attachments
* BrokerableAttachment::kNonceSize
;
160 if (pickle_len
> max_size_t
- attachment_length
)
163 // Check whether the range includes the attachments.
164 size_t buffer_length
= static_cast<size_t>(range_end
- range_start
);
165 if (buffer_length
< attachment_length
+ pickle_len
)
168 for (int i
= 0; i
< num_attachments
; ++i
) {
169 const char* attachment_start
=
170 pickle_end
+ i
* BrokerableAttachment::kNonceSize
;
171 BrokerableAttachment::AttachmentId
id(attachment_start
,
172 BrokerableAttachment::kNonceSize
);
173 info
->attachment_ids
.push_back(id
);
176 pickle_end
+ num_attachments
* BrokerableAttachment::kNonceSize
;
178 info
->message_end
= pickle_end
;
179 #endif // USE_ATTACHMENT_BROKER
181 info
->message_found
= true;
184 bool Message::AddPlaceholderBrokerableAttachmentWithId(
185 BrokerableAttachment::AttachmentId id
) {
186 scoped_refptr
<PlaceholderBrokerableAttachment
> attachment(
187 new PlaceholderBrokerableAttachment(id
));
188 return attachment_set()->AddAttachment(attachment
);
191 bool Message::WriteAttachment(scoped_refptr
<MessageAttachment
> attachment
) {
192 // We write the index of the descriptor so that we don't have to
193 // keep the current descriptor as extra decoding state when deserialising.
194 WriteInt(attachment_set()->size());
195 return attachment_set()->AddAttachment(attachment
);
198 bool Message::ReadAttachment(
199 base::PickleIterator
* iter
,
200 scoped_refptr
<MessageAttachment
>* attachment
) const {
201 int descriptor_index
;
202 if (!iter
->ReadInt(&descriptor_index
))
205 MessageAttachmentSet
* attachment_set
= attachment_set_
.get();
209 *attachment
= attachment_set
->GetAttachmentAt(descriptor_index
);
210 return nullptr != attachment
->get();
213 bool Message::HasAttachments() const {
214 return attachment_set_
.get() && !attachment_set_
->empty();
217 bool Message::HasMojoHandles() const {
218 return attachment_set_
.get() && attachment_set_
->num_mojo_handles() > 0;
221 bool Message::HasBrokerableAttachments() const {
222 return attachment_set_
.get() &&
223 attachment_set_
->num_brokerable_attachments() > 0;