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"
7 #include "base/atomic_sequence_num.h"
8 #include "base/logging.h"
9 #include "build/build_config.h"
10 #include "ipc/ipc_message_attachment.h"
11 #include "ipc/ipc_message_attachment_set.h"
12 #include "ipc/placeholder_brokerable_attachment.h"
15 #include "base/file_descriptor_posix.h"
16 #include "ipc/ipc_platform_file_attachment_posix.h"
21 base::StaticAtomicSequenceNumber g_ref_num
;
23 // Create a reference number for identifying IPC messages in traces. The return
24 // values has the reference number stored in the upper 24 bits, leaving the low
25 // 8 bits set to 0 for use as flags.
26 inline uint32
GetRefNumUpper24() {
27 base::trace_event::TraceLog
* trace_log
=
28 base::trace_event::TraceLog::GetInstance();
29 uint32 pid
= trace_log
? trace_log
->process_id() : 0;
30 uint32 count
= g_ref_num
.GetNext();
31 // The 24 bit hash is composed of 14 bits of the count and 10 bits of the
32 // Process ID. With the current trace event buffer cap, the 14-bit count did
33 // not appear to wrap during a trace. Note that it is not a big deal if
34 // collisions occur, as this is only used for debugging and trace analysis.
35 return ((pid
<< 14) | (count
& 0x3fff)) << 8;
42 //------------------------------------------------------------------------------
47 Message::Message() : base::Pickle(sizeof(Header
)) {
48 header()->routing
= header()->type
= 0;
49 header()->flags
= GetRefNumUpper24();
50 #if USE_ATTACHMENT_BROKER
51 header()->num_brokered_attachments
= 0;
54 header()->num_fds
= 0;
60 Message::Message(int32 routing_id
, uint32 type
, PriorityValue priority
)
61 : base::Pickle(sizeof(Header
)) {
62 header()->routing
= routing_id
;
63 header()->type
= type
;
64 DCHECK((priority
& 0xffffff00) == 0);
65 header()->flags
= priority
| GetRefNumUpper24();
66 #if USE_ATTACHMENT_BROKER
67 header()->num_brokered_attachments
= 0;
70 header()->num_fds
= 0;
76 Message::Message(const char* data
, int data_len
)
77 : base::Pickle(data
, data_len
) {
81 Message::Message(const Message
& other
) : base::Pickle(other
) {
83 attachment_set_
= other
.attachment_set_
;
86 void Message::Init() {
87 dispatch_error_
= false;
88 sender_pid_
= base::kNullProcessId
;
89 #ifdef IPC_MESSAGE_LOG_ENABLED
96 Message
& Message::operator=(const Message
& other
) {
97 *static_cast<base::Pickle
*>(this) = other
;
98 attachment_set_
= other
.attachment_set_
;
102 void Message::SetHeaderValues(int32 routing
, uint32 type
, uint32 flags
) {
103 // This should only be called when the message is already empty.
104 DCHECK(payload_size() == 0);
106 header()->routing
= routing
;
107 header()->type
= type
;
108 header()->flags
= flags
;
111 void Message::EnsureMessageAttachmentSet() {
112 if (attachment_set_
.get() == NULL
)
113 attachment_set_
= new MessageAttachmentSet
;
116 #ifdef IPC_MESSAGE_LOG_ENABLED
117 void Message::set_sent_time(int64 time
) {
118 DCHECK((header()->flags
& HAS_SENT_TIME_BIT
) == 0);
119 header()->flags
|= HAS_SENT_TIME_BIT
;
123 int64
Message::sent_time() const {
124 if ((header()->flags
& HAS_SENT_TIME_BIT
) == 0)
127 const char* data
= end_of_payload();
128 data
-= sizeof(int64
);
129 return *(reinterpret_cast<const int64
*>(data
));
132 void Message::set_received_time(int64 time
) const {
133 received_time_
= time
;
137 Message::NextMessageInfo::NextMessageInfo()
138 : message_found(false), pickle_end(nullptr), message_end(nullptr) {}
139 Message::NextMessageInfo::~NextMessageInfo() {}
142 Message::NextMessageInfo
Message::FindNext(const char* range_start
,
143 const char* range_end
) {
144 NextMessageInfo info
;
145 const char* pickle_end
=
146 base::Pickle::FindNext(sizeof(Header
), range_start
, range_end
);
147 if (pickle_end
== nullptr)
149 info
.pickle_end
= pickle_end
;
151 #if USE_ATTACHMENT_BROKER
152 // The data is not copied.
153 size_t pickle_len
= static_cast<size_t>(pickle_end
- range_start
);
154 Message
message(range_start
, static_cast<int>(pickle_len
));
155 int num_attachments
= message
.header()->num_brokered_attachments
;
157 // Each brokered attachment adds kNonceSize bytes of data to the message. We
158 // want to avoid overflows in our computations, so we limit the number of
159 // brokerable attachments to 100.
160 if (num_attachments
> 100)
163 // Check whether the range includes the attachments.
164 size_t attachment_length
= num_attachments
* BrokerableAttachment::kNonceSize
;
165 size_t buffer_length
= static_cast<size_t>(range_end
- range_start
);
166 if (buffer_length
< attachment_length
+ pickle_len
)
169 for (int i
= 0; i
< num_attachments
; ++i
) {
170 const char* attachment_start
=
171 pickle_end
+ i
* (BrokerableAttachment::kNonceSize
);
172 BrokerableAttachment::AttachmentId
id(attachment_start
,
173 BrokerableAttachment::kNonceSize
);
174 info
.attachment_ids
.push_back(id
);
177 pickle_end
+ num_attachments
* BrokerableAttachment::kNonceSize
;
179 info
.message_end
= pickle_end
;
180 #endif // USE_ATTACHMENT_BROKER
182 info
.message_found
= true;
186 Message::SerializedAttachmentIds
187 Message::SerializedIdsOfBrokerableAttachments() {
188 DCHECK(HasBrokerableAttachments());
189 std::vector
<const BrokerableAttachment
*> attachments
=
190 attachment_set_
->PeekBrokerableAttachments();
191 size_t size
= attachments
.size() * BrokerableAttachment::kNonceSize
;
192 char* buffer
= static_cast<char*>(malloc(size
));
193 for (size_t i
= 0; i
< attachments
.size(); ++i
) {
194 const BrokerableAttachment
* attachment
= attachments
[i
];
195 char* start_range
= buffer
+ i
* BrokerableAttachment::kNonceSize
;
196 BrokerableAttachment::AttachmentId id
= attachment
->GetIdentifier();
197 id
.SerializeToBuffer(start_range
, BrokerableAttachment::kNonceSize
);
199 SerializedAttachmentIds ids
;
205 bool Message::AddPlaceholderBrokerableAttachmentWithId(
206 BrokerableAttachment::AttachmentId id
) {
207 scoped_refptr
<PlaceholderBrokerableAttachment
> attachment(
208 new PlaceholderBrokerableAttachment(id
));
209 return attachment_set()->AddAttachment(attachment
);
212 bool Message::WriteAttachment(scoped_refptr
<MessageAttachment
> attachment
) {
213 // We write the index of the descriptor so that we don't have to
214 // keep the current descriptor as extra decoding state when deserialising.
215 WriteInt(attachment_set()->size());
217 #if USE_ATTACHMENT_BROKER
218 if (attachment
->GetType() == MessageAttachment::TYPE_BROKERABLE_ATTACHMENT
)
219 header()->num_brokered_attachments
+= 1;
222 return attachment_set()->AddAttachment(attachment
);
225 bool Message::ReadAttachment(
226 base::PickleIterator
* iter
,
227 scoped_refptr
<MessageAttachment
>* attachment
) const {
228 int descriptor_index
;
229 if (!iter
->ReadInt(&descriptor_index
))
232 MessageAttachmentSet
* attachment_set
= attachment_set_
.get();
236 *attachment
= attachment_set
->GetAttachmentAt(descriptor_index
);
237 return nullptr != attachment
->get();
240 bool Message::HasAttachments() const {
241 return attachment_set_
.get() && !attachment_set_
->empty();
244 bool Message::HasMojoHandles() const {
245 return attachment_set_
.get() && attachment_set_
->num_mojo_handles() > 0;
248 bool Message::HasBrokerableAttachments() const {
249 return attachment_set_
.get() &&
250 attachment_set_
->num_brokerable_attachments() > 0;