| Index: mojo/public/cpp/bindings/binding_set.h | 
| diff --git a/mojo/public/cpp/bindings/binding_set.h b/mojo/public/cpp/bindings/binding_set.h | 
| index 69f17cc0f1cf1ecb0ec4e58e38d8952586e52511..ef5834cca054152df19c1bc0b644140ef01795d5 100644 | 
| --- a/mojo/public/cpp/bindings/binding_set.h | 
| +++ b/mojo/public/cpp/bindings/binding_set.h | 
| @@ -35,11 +35,14 @@ enum class BindingSetDispatchMode { | 
| WITH_CONTEXT, | 
| }; | 
|  | 
| +using BindingId = size_t; | 
| + | 
| // Use this class to manage a set of bindings, which are automatically destroyed | 
| // and removed from the set when the pipe they are bound to is disconnected. | 
| template <typename Interface, typename BindingType = Binding<Interface>> | 
| class BindingSet { | 
| public: | 
| +  using PreDispatchCallback = base::Callback<void(void*)>; | 
| using Traits = BindingSetTraits<BindingType>; | 
| using ProxyType = typename Traits::ProxyType; | 
| using RequestType = typename Traits::RequestType; | 
| @@ -57,25 +60,54 @@ class BindingSet { | 
| error_handler_ = error_handler; | 
| } | 
|  | 
| +  // Sets a callback to be invoked immediately before dispatching any message or | 
| +  // error received by any of the bindings in the set. This may only be used | 
| +  // if the set was constructed with |BindingSetDispatchMode::WITH_CONTEXT|. | 
| +  // |handler| is passed the context associated with the binding which received | 
| +  // the message or event about to be dispatched. | 
| +  void set_pre_dispatch_handler(const PreDispatchCallback& handler) { | 
| +    DCHECK(SupportsContext()); | 
| +    pre_dispatch_handler_ = handler; | 
| +  } | 
| + | 
| // Adds a new binding to the set which binds |request| to |impl|. If |context| | 
| // is non-null, dispatch_context() will reflect this value during the extent | 
| // of any message or error dispatch targeting this specific binding. Note that | 
| // |context| may only be non-null if the BindingSet was constructed with | 
| // |BindingSetDispatchMode::WITH_CONTEXT|. | 
| -  void AddBinding(Interface* impl, | 
| -                  RequestType request, | 
| -                  void* context = nullptr) { | 
| +  BindingId AddBinding(Interface* impl, | 
| +                     RequestType request, | 
| +                     void* context = nullptr) { | 
| DCHECK(!context || SupportsContext()); | 
| +    BindingId id = next_binding_id_++; | 
| +    DCHECK_GE(next_binding_id_, 0u); | 
| std::unique_ptr<Entry> entry = | 
| -        base::MakeUnique<Entry>(impl, std::move(request), this, context); | 
| -    bindings_.insert(std::make_pair(entry.get(), std::move(entry))); | 
| +        base::MakeUnique<Entry>(impl, std::move(request), this, id, context); | 
| +    bindings_.insert(std::make_pair(id, std::move(entry))); | 
| +    return id; | 
| +  } | 
| + | 
| +  // Removes a binding from the set. Note that this is safe to call even if the | 
| +  // binding corresponding to |id| has already been removed. | 
| +  // | 
| +  // Returns |true| if the binding was removed and |false| if it didn't exist. | 
| +  bool RemoveBinding(BindingId id) { | 
| +    auto it = bindings_.find(id); | 
| +    if (it == bindings_.end()) | 
| +      return false; | 
| +    bindings_.erase(it); | 
| +    return true; | 
| } | 
|  | 
| // Returns a proxy bound to one end of a pipe whose other end is bound to | 
| -  // |this|. | 
| -  ProxyType CreateInterfacePtrAndBind(Interface* impl) { | 
| +  // |this|. If |id_storage| is not null, |*id_storage| will be set to the ID | 
| +  // of the added binding. | 
| +  ProxyType CreateInterfacePtrAndBind(Interface* impl, | 
| +                                      BindingId* id_storage = nullptr) { | 
| ProxyType proxy; | 
| -    AddBinding(impl, Traits::GetProxy(&proxy)); | 
| +    BindingId id = AddBinding(impl, Traits::GetProxy(&proxy)); | 
| +    if (id_storage) | 
| +      *id_storage = id; | 
| return proxy; | 
| } | 
|  | 
| @@ -109,9 +141,11 @@ class BindingSet { | 
| Entry(Interface* impl, | 
| RequestType request, | 
| BindingSet* binding_set, | 
| +          BindingId binding_id, | 
| void* context) | 
| : binding_(impl, std::move(request)), | 
| binding_set_(binding_set), | 
| +          binding_id_(binding_id), | 
| context_(context) { | 
| if (binding_set->SupportsContext()) | 
| binding_.AddFilter(base::MakeUnique<DispatchFilter>(this)); | 
| @@ -147,11 +181,12 @@ class BindingSet { | 
| void OnConnectionError() { | 
| if (binding_set_->SupportsContext()) | 
| WillDispatch(); | 
| -      binding_set_->OnConnectionError(this); | 
| +      binding_set_->OnConnectionError(binding_id_); | 
| } | 
|  | 
| BindingType binding_; | 
| BindingSet* const binding_set_; | 
| +    const BindingId binding_id_; | 
| void* const context_; | 
|  | 
| DISALLOW_COPY_AND_ASSIGN(Entry); | 
| @@ -160,14 +195,16 @@ class BindingSet { | 
| void SetDispatchContext(void* context) { | 
| DCHECK(SupportsContext()); | 
| dispatch_context_ = context; | 
| +    if (!pre_dispatch_handler_.is_null()) | 
| +      pre_dispatch_handler_.Run(context); | 
| } | 
|  | 
| bool SupportsContext() const { | 
| return dispatch_mode_ == BindingSetDispatchMode::WITH_CONTEXT; | 
| } | 
|  | 
| -  void OnConnectionError(Entry* entry) { | 
| -    auto it = bindings_.find(entry); | 
| +  void OnConnectionError(BindingId id) { | 
| +    auto it = bindings_.find(id); | 
| DCHECK(it != bindings_.end()); | 
| bindings_.erase(it); | 
|  | 
| @@ -177,7 +214,9 @@ class BindingSet { | 
|  | 
| BindingSetDispatchMode dispatch_mode_; | 
| base::Closure error_handler_; | 
| -  std::map<Entry*, std::unique_ptr<Entry>> bindings_; | 
| +  PreDispatchCallback pre_dispatch_handler_; | 
| +  BindingId next_binding_id_ = 0; | 
| +  std::map<BindingId, std::unique_ptr<Entry>> bindings_; | 
| void* dispatch_context_ = nullptr; | 
|  | 
| DISALLOW_COPY_AND_ASSIGN(BindingSet); | 
|  |