Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * vim: sw=4 ts=4 et : |
michael@0 | 3 | */ |
michael@0 | 4 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 7 | |
michael@0 | 8 | #ifndef mozilla_ipc_ProtocolUtils_h |
michael@0 | 9 | #define mozilla_ipc_ProtocolUtils_h 1 |
michael@0 | 10 | |
michael@0 | 11 | #include "base/process.h" |
michael@0 | 12 | #include "base/process_util.h" |
michael@0 | 13 | #include "chrome/common/ipc_message_utils.h" |
michael@0 | 14 | |
michael@0 | 15 | #include "prenv.h" |
michael@0 | 16 | |
michael@0 | 17 | #include "IPCMessageStart.h" |
michael@0 | 18 | #include "mozilla/Attributes.h" |
michael@0 | 19 | #include "mozilla/ipc/FileDescriptor.h" |
michael@0 | 20 | #include "mozilla/ipc/Shmem.h" |
michael@0 | 21 | #include "mozilla/ipc/Transport.h" |
michael@0 | 22 | #include "mozilla/ipc/MessageLink.h" |
michael@0 | 23 | #include "mozilla/LinkedList.h" |
michael@0 | 24 | |
michael@0 | 25 | #if defined(ANDROID) && defined(DEBUG) |
michael@0 | 26 | #include <android/log.h> |
michael@0 | 27 | #endif |
michael@0 | 28 | |
michael@0 | 29 | // WARNING: this takes into account the private, special-message-type |
michael@0 | 30 | // enum in ipc_channel.h. They need to be kept in sync. |
michael@0 | 31 | namespace { |
michael@0 | 32 | // XXX the max message ID is actually kuint32max now ... when this |
michael@0 | 33 | // changed, the assumptions of the special message IDs changed in that |
michael@0 | 34 | // they're not carving out messages from likely-unallocated space, but |
michael@0 | 35 | // rather carving out messages from the end of space allocated to |
michael@0 | 36 | // protocol 0. Oops! We can get away with this until protocol 0 |
michael@0 | 37 | // starts approaching its 65,536th message. |
michael@0 | 38 | enum { |
michael@0 | 39 | CHANNEL_OPENED_MESSAGE_TYPE = kuint16max - 5, |
michael@0 | 40 | SHMEM_DESTROYED_MESSAGE_TYPE = kuint16max - 4, |
michael@0 | 41 | SHMEM_CREATED_MESSAGE_TYPE = kuint16max - 3, |
michael@0 | 42 | GOODBYE_MESSAGE_TYPE = kuint16max - 2 |
michael@0 | 43 | |
michael@0 | 44 | // kuint16max - 1 is used by ipc_channel.h. |
michael@0 | 45 | }; |
michael@0 | 46 | } |
michael@0 | 47 | |
michael@0 | 48 | namespace mozilla { |
michael@0 | 49 | namespace dom { |
michael@0 | 50 | class ContentParent; |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | namespace net { |
michael@0 | 54 | class NeckoParent; |
michael@0 | 55 | } |
michael@0 | 56 | |
michael@0 | 57 | namespace ipc { |
michael@0 | 58 | |
michael@0 | 59 | #ifdef XP_WIN |
michael@0 | 60 | const base::ProcessHandle kInvalidProcessHandle = INVALID_HANDLE_VALUE; |
michael@0 | 61 | #else |
michael@0 | 62 | const base::ProcessHandle kInvalidProcessHandle = -1; |
michael@0 | 63 | #endif |
michael@0 | 64 | |
michael@0 | 65 | class ProtocolFdMapping; |
michael@0 | 66 | class ProtocolCloneContext; |
michael@0 | 67 | |
michael@0 | 68 | // Used to pass references to protocol actors across the wire. |
michael@0 | 69 | // Actors created on the parent-side have a positive ID, and actors |
michael@0 | 70 | // allocated on the child side have a negative ID. |
michael@0 | 71 | struct ActorHandle |
michael@0 | 72 | { |
michael@0 | 73 | int mId; |
michael@0 | 74 | }; |
michael@0 | 75 | |
michael@0 | 76 | // Used internally to represent a "trigger" that might cause a state |
michael@0 | 77 | // transition. Triggers are normalized across parent+child to Send |
michael@0 | 78 | // and Recv (instead of child-in, child-out, parent-in, parent-out) so |
michael@0 | 79 | // that they can share the same state machine implementation. To |
michael@0 | 80 | // further normalize, |Send| is used for 'call', |Recv| for 'answer'. |
michael@0 | 81 | struct Trigger |
michael@0 | 82 | { |
michael@0 | 83 | enum Action { Send, Recv }; |
michael@0 | 84 | |
michael@0 | 85 | Trigger(Action action, int32_t msg) : |
michael@0 | 86 | mAction(action), |
michael@0 | 87 | mMsg(msg) |
michael@0 | 88 | {} |
michael@0 | 89 | |
michael@0 | 90 | Action mAction; |
michael@0 | 91 | int32_t mMsg; |
michael@0 | 92 | }; |
michael@0 | 93 | |
michael@0 | 94 | class ProtocolCloneContext |
michael@0 | 95 | { |
michael@0 | 96 | typedef mozilla::dom::ContentParent ContentParent; |
michael@0 | 97 | typedef mozilla::net::NeckoParent NeckoParent; |
michael@0 | 98 | |
michael@0 | 99 | ContentParent* mContentParent; |
michael@0 | 100 | NeckoParent* mNeckoParent; |
michael@0 | 101 | |
michael@0 | 102 | public: |
michael@0 | 103 | ProtocolCloneContext() |
michael@0 | 104 | : mContentParent(nullptr) |
michael@0 | 105 | , mNeckoParent(nullptr) |
michael@0 | 106 | {} |
michael@0 | 107 | |
michael@0 | 108 | void SetContentParent(ContentParent* aContentParent) |
michael@0 | 109 | { |
michael@0 | 110 | mContentParent = aContentParent; |
michael@0 | 111 | } |
michael@0 | 112 | |
michael@0 | 113 | ContentParent* GetContentParent() { return mContentParent; } |
michael@0 | 114 | |
michael@0 | 115 | void SetNeckoParent(NeckoParent* aNeckoParent) |
michael@0 | 116 | { |
michael@0 | 117 | mNeckoParent = aNeckoParent; |
michael@0 | 118 | } |
michael@0 | 119 | |
michael@0 | 120 | NeckoParent* GetNeckoParent() { return mNeckoParent; } |
michael@0 | 121 | }; |
michael@0 | 122 | |
michael@0 | 123 | template<class ListenerT> |
michael@0 | 124 | class /*NS_INTERFACE_CLASS*/ IProtocolManager |
michael@0 | 125 | { |
michael@0 | 126 | public: |
michael@0 | 127 | enum ActorDestroyReason { |
michael@0 | 128 | FailedConstructor, |
michael@0 | 129 | Deletion, |
michael@0 | 130 | AncestorDeletion, |
michael@0 | 131 | NormalShutdown, |
michael@0 | 132 | AbnormalShutdown |
michael@0 | 133 | }; |
michael@0 | 134 | |
michael@0 | 135 | typedef base::ProcessHandle ProcessHandle; |
michael@0 | 136 | |
michael@0 | 137 | virtual int32_t Register(ListenerT*) = 0; |
michael@0 | 138 | virtual int32_t RegisterID(ListenerT*, int32_t) = 0; |
michael@0 | 139 | virtual ListenerT* Lookup(int32_t) = 0; |
michael@0 | 140 | virtual void Unregister(int32_t) = 0; |
michael@0 | 141 | virtual void RemoveManagee(int32_t, ListenerT*) = 0; |
michael@0 | 142 | |
michael@0 | 143 | virtual Shmem::SharedMemory* CreateSharedMemory( |
michael@0 | 144 | size_t, SharedMemory::SharedMemoryType, bool, int32_t*) = 0; |
michael@0 | 145 | virtual bool AdoptSharedMemory(Shmem::SharedMemory*, int32_t*) = 0; |
michael@0 | 146 | virtual Shmem::SharedMemory* LookupSharedMemory(int32_t) = 0; |
michael@0 | 147 | virtual bool IsTrackingSharedMemory(Shmem::SharedMemory*) = 0; |
michael@0 | 148 | virtual bool DestroySharedMemory(Shmem&) = 0; |
michael@0 | 149 | |
michael@0 | 150 | // XXX odd ducks, acknowledged |
michael@0 | 151 | virtual ProcessHandle OtherProcess() const = 0; |
michael@0 | 152 | virtual MessageChannel* GetIPCChannel() = 0; |
michael@0 | 153 | |
michael@0 | 154 | // The implementation of function is generated by code generator. |
michael@0 | 155 | virtual void CloneManagees(ListenerT* aSource, |
michael@0 | 156 | ProtocolCloneContext* aCtx) = 0; |
michael@0 | 157 | }; |
michael@0 | 158 | |
michael@0 | 159 | typedef IPCMessageStart ProtocolId; |
michael@0 | 160 | |
michael@0 | 161 | /** |
michael@0 | 162 | * All RPC protocols should implement this interface. |
michael@0 | 163 | */ |
michael@0 | 164 | class IProtocol : protected MessageListener |
michael@0 | 165 | { |
michael@0 | 166 | public: |
michael@0 | 167 | /** |
michael@0 | 168 | * This function is used to clone this protocol actor. |
michael@0 | 169 | * |
michael@0 | 170 | * see IProtocol::CloneProtocol() |
michael@0 | 171 | */ |
michael@0 | 172 | virtual IProtocol* |
michael@0 | 173 | CloneProtocol(MessageChannel* aChannel, |
michael@0 | 174 | ProtocolCloneContext* aCtx) = 0; |
michael@0 | 175 | }; |
michael@0 | 176 | |
michael@0 | 177 | /** |
michael@0 | 178 | * All top-level protocols should inherit this class. |
michael@0 | 179 | * |
michael@0 | 180 | * IToplevelProtocol tracks all top-level protocol actors created from |
michael@0 | 181 | * this protocol actor. |
michael@0 | 182 | */ |
michael@0 | 183 | class IToplevelProtocol : public LinkedListElement<IToplevelProtocol> |
michael@0 | 184 | { |
michael@0 | 185 | protected: |
michael@0 | 186 | IToplevelProtocol(ProtocolId aProtoId) |
michael@0 | 187 | : mProtocolId(aProtoId) |
michael@0 | 188 | , mTrans(nullptr) |
michael@0 | 189 | { |
michael@0 | 190 | } |
michael@0 | 191 | |
michael@0 | 192 | ~IToplevelProtocol(); |
michael@0 | 193 | |
michael@0 | 194 | /** |
michael@0 | 195 | * Add an actor to the list of actors that have been opened by this |
michael@0 | 196 | * protocol. |
michael@0 | 197 | */ |
michael@0 | 198 | void AddOpenedActor(IToplevelProtocol* aActor); |
michael@0 | 199 | |
michael@0 | 200 | public: |
michael@0 | 201 | void SetTransport(Transport* aTrans) |
michael@0 | 202 | { |
michael@0 | 203 | mTrans = aTrans; |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | Transport* GetTransport() const { return mTrans; } |
michael@0 | 207 | |
michael@0 | 208 | ProtocolId GetProtocolId() const { return mProtocolId; } |
michael@0 | 209 | |
michael@0 | 210 | /** |
michael@0 | 211 | * Return first of actors of top level protocols opened by this one. |
michael@0 | 212 | */ |
michael@0 | 213 | IToplevelProtocol* GetFirstOpenedActors() |
michael@0 | 214 | { |
michael@0 | 215 | return mOpenActors.getFirst(); |
michael@0 | 216 | } |
michael@0 | 217 | const IToplevelProtocol* GetFirstOpenedActors() const |
michael@0 | 218 | { |
michael@0 | 219 | return mOpenActors.getFirst(); |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | virtual IToplevelProtocol* |
michael@0 | 223 | CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds, |
michael@0 | 224 | base::ProcessHandle aPeerProcess, |
michael@0 | 225 | ProtocolCloneContext* aCtx); |
michael@0 | 226 | |
michael@0 | 227 | void CloneOpenedToplevels(IToplevelProtocol* aTemplate, |
michael@0 | 228 | const InfallibleTArray<ProtocolFdMapping>& aFds, |
michael@0 | 229 | base::ProcessHandle aPeerProcess, |
michael@0 | 230 | ProtocolCloneContext* aCtx); |
michael@0 | 231 | |
michael@0 | 232 | private: |
michael@0 | 233 | LinkedList<IToplevelProtocol> mOpenActors; // All protocol actors opened by this. |
michael@0 | 234 | |
michael@0 | 235 | ProtocolId mProtocolId; |
michael@0 | 236 | Transport* mTrans; |
michael@0 | 237 | }; |
michael@0 | 238 | |
michael@0 | 239 | |
michael@0 | 240 | inline bool |
michael@0 | 241 | LoggingEnabled() |
michael@0 | 242 | { |
michael@0 | 243 | #if defined(DEBUG) |
michael@0 | 244 | return !!PR_GetEnv("MOZ_IPC_MESSAGE_LOG"); |
michael@0 | 245 | #else |
michael@0 | 246 | return false; |
michael@0 | 247 | #endif |
michael@0 | 248 | } |
michael@0 | 249 | |
michael@0 | 250 | MOZ_NEVER_INLINE void |
michael@0 | 251 | ProtocolErrorBreakpoint(const char* aMsg); |
michael@0 | 252 | |
michael@0 | 253 | MOZ_NEVER_INLINE void |
michael@0 | 254 | FatalError(const char* aProtocolName, const char* aMsg, |
michael@0 | 255 | base::ProcessHandle aHandle, bool aIsParent); |
michael@0 | 256 | |
michael@0 | 257 | struct PrivateIPDLInterface {}; |
michael@0 | 258 | |
michael@0 | 259 | bool |
michael@0 | 260 | Bridge(const PrivateIPDLInterface&, |
michael@0 | 261 | MessageChannel*, base::ProcessHandle, MessageChannel*, base::ProcessHandle, |
michael@0 | 262 | ProtocolId, ProtocolId); |
michael@0 | 263 | |
michael@0 | 264 | bool |
michael@0 | 265 | Open(const PrivateIPDLInterface&, |
michael@0 | 266 | MessageChannel*, base::ProcessHandle, Transport::Mode, |
michael@0 | 267 | ProtocolId, ProtocolId); |
michael@0 | 268 | |
michael@0 | 269 | bool |
michael@0 | 270 | UnpackChannelOpened(const PrivateIPDLInterface&, |
michael@0 | 271 | const IPC::Message&, |
michael@0 | 272 | TransportDescriptor*, base::ProcessId*, ProtocolId*); |
michael@0 | 273 | |
michael@0 | 274 | } // namespace ipc |
michael@0 | 275 | } // namespace mozilla |
michael@0 | 276 | |
michael@0 | 277 | |
michael@0 | 278 | namespace IPC { |
michael@0 | 279 | |
michael@0 | 280 | template <> |
michael@0 | 281 | struct ParamTraits<mozilla::ipc::ActorHandle> |
michael@0 | 282 | { |
michael@0 | 283 | typedef mozilla::ipc::ActorHandle paramType; |
michael@0 | 284 | |
michael@0 | 285 | static void Write(Message* aMsg, const paramType& aParam) |
michael@0 | 286 | { |
michael@0 | 287 | IPC::WriteParam(aMsg, aParam.mId); |
michael@0 | 288 | } |
michael@0 | 289 | |
michael@0 | 290 | static bool Read(const Message* aMsg, void** aIter, paramType* aResult) |
michael@0 | 291 | { |
michael@0 | 292 | int id; |
michael@0 | 293 | if (IPC::ReadParam(aMsg, aIter, &id)) { |
michael@0 | 294 | aResult->mId = id; |
michael@0 | 295 | return true; |
michael@0 | 296 | } |
michael@0 | 297 | return false; |
michael@0 | 298 | } |
michael@0 | 299 | |
michael@0 | 300 | static void Log(const paramType& aParam, std::wstring* aLog) |
michael@0 | 301 | { |
michael@0 | 302 | aLog->append(StringPrintf(L"(%d)", aParam.mId)); |
michael@0 | 303 | } |
michael@0 | 304 | }; |
michael@0 | 305 | |
michael@0 | 306 | } // namespace IPC |
michael@0 | 307 | |
michael@0 | 308 | |
michael@0 | 309 | #endif // mozilla_ipc_ProtocolUtils_h |